0
点赞
收藏
分享

微信扫一扫

(线段树)lintcode中等205区间最小数

素锦时年_1b00 2022-04-19 阅读 56

题目

描述
给定一个整数数组(下标由 0 到 n-1,其中 n 表示数组的规模),以及一个查询列表。每一个查询列表有两个整数 [start, end]。 对于每个查询,计算出数组中从下标 start 到 end 之间的数的最小值,并返回在结果列表中。

样例

样例1:
输入:数组 :[1,2,7,8,5] 查询 :[(1,2),(0,4),(2,4)]。输出:[2,1,5]
样例2:
输入:数组 :[4,5,7,1] 查询 :[(1,2),(1,3)]。输出:[5,1]

挑战
每次查询在O(logN)的时间内完成

分析

这道题如果用暴力的方法非常好想,每次查询遍历一遍查询区间,时间复杂度O(n),但是当查询次数非常多可能造成很多重复的情况,例如[0,4],[0,5],查完第一个区间后只需要跟下标为5的元素进行比较即可得出第二个的结果,所以这里我们用到了线段树

代码部分

1.线段树节点

//线段树节点 
class SegmentTreeNode
{
public:
	int start,end;
	int minval;
	SegmentTreeNode* left;		//左右区间
	SegmentTreeNode* right;
	SegmentTreeNode(int s,int e,int m):start(s),end(e),minval(m) 
	{
		left=NULL;
		right=NULL;
	}
		
};

2.线段树

线段树构造

大体思路:创建一个节点,递归的创建它的左右区间节点,然后回溯的地方将左右区间的最小值赋值给当前节点

	SegmentTreeNode* build(int start,int end,vector<int> &nums)
	{
		//特判
		if(start>end)
			return NULL;
		
		if(start==end)
			return new SegmentTreeNode(start,end,nums[start]);
		
		SegmentTreeNode* root=new SegmentTreeNode(start,end,0xffffff);	
		int mid=(start+end)/2;
		root->left=build(start,mid,nums);
		root->right=build(mid+1,end,nums);
		
		if(root->left!=NULL)
			root->minval=min(root->minval,root->left->minval);
		
		if(root->right!=NULL)
			root->minval=min(root->minval,root->right->minval);
			
		return root;
	}
线段树查询

也是一个递归查询过程

当前能做的事情:递归的查询左右区间的最小值,将左右区间较小的那个值返回

出口:当区间跟查询区间没有重合部分直接返回一个大值(因为我们要求最小值),当区间在查询区间中的时候直接返回当前节点的最小值

	int querymin(SegmentTreeNode* _root,int start,int end,int qstart,int qend)
	{
		//出口
		if(qend<start||qstart>end)
		{
			return 0xffffff;
		}
		
		if(qstart<=start&&qend>=end)
		{
			return _root->minval;
		}
		//现在能做的事情
		int mid=(start+end)/2;
		int leftmin=querymin(_root->left,start,mid,qstart,qend);
		int rightmin=querymin(_root->right,mid+1,end,qstart,qend);
		
		return min(leftmin,rightmin); 
	}

3.解题部分

特判断一下给定数组为空或查询列表为空时,直接返回一个空数组

创建线段树后直接循环的遍历每次查询,将结果存到答案数组中

		SegmentTree st(a);
		for(int i=0;i<len;i++)
		{
			int start=queries[i].start;
			int end=queries[i].end;
			int minval=st.querymin(st.root,0,a.size()-1,start,end);
			ans.push_back(minval);
		}

完整代码

#include <bits/stdc++.h>
using namespace std;

class Interval
{
public:
    int start, end;
    Interval(int start, int end)
	{
    	this->start = start;
    	this->end = end;
    }
};


//线段树节点 
class SegmentTreeNode
{
public:
	int start,end;
	int minval;
	SegmentTreeNode* left;		//左右区间
	SegmentTreeNode* right;
	SegmentTreeNode(int s,int e,int m):start(s),end(e),minval(m) 
	{
		left=NULL;
		right=NULL;
	}
		
};


//线段树 
class SegmentTree
{
public:
	SegmentTreeNode *root;	//根节点
	
	SegmentTree(vector<int> nums)
	{
		root=build(0,nums.size()-1,nums);
	}
	
	SegmentTreeNode* build(int start,int end,vector<int> &nums)
	{
		//特判
		if(start>end)
			return NULL;
		
		if(start==end)
			return new SegmentTreeNode(start,end,nums[start]);
		
		SegmentTreeNode* root=new SegmentTreeNode(start,end,0xffffff);	
		int mid=(start+end)/2;
		root->left=build(start,mid,nums);
		root->right=build(mid+1,end,nums);
		
		if(root->left!=NULL)
			root->minval=min(root->minval,root->left->minval);
		
		if(root->right!=NULL)
			root->minval=min(root->minval,root->right->minval);
			
		return root;
	}
	
	int querymin(SegmentTreeNode* _root,int start,int end,int qstart,int qend)
	{
		//出口
		if(qend<start||qstart>end)
		{
			return 0xffffff;
		}
		
		if(qstart<=start&&qend>=end)
		{
			return _root->minval;
		}
		//现在能做的事情
		int mid=(start+end)/2;
		int leftmin=querymin(_root->left,start,mid,qstart,qend);
		int rightmin=querymin(_root->right,mid+1,end,qstart,qend);
		
		return min(leftmin,rightmin); 
	} 
		
};


class Solution {
public:
    vector<int> intervalMinNumber(vector<int> &a, vector<Interval> &queries) {
		vector<int> ans;
		int len=queries.size();
		if(len==0||a.size()==0)	//特判 
			return ans;
		
		SegmentTree st(a);
		for(int i=0;i<len;i++)
		{
			int start=queries[i].start;
			int end=queries[i].end;
			int minval=st.querymin(st.root,0,a.size()-1,start,end);
			ans.push_back(minval);
		}
		
		return ans;
    }
};


int main (void)
{
	vector<int> nums={1,2,7,8,5};
	vector<Interval> queries={	Interval(1,2),Interval(0,4),Interval(2,4)	};
	Solution s;
	vector<int> ans;
	ans=s.intervalMinNumber(nums,queries);
	
	for(int i=0;i<ans.size();i++)
		cout<<ans[i]<<" ";
		
	return 0;
}






总结

在练习运用这些模板时,主要练习两个方面
1.遇到一道题能想到运用的模板和时间复杂度空间复杂度
2.学习模板的思路后,自己的代码实现能力(如何把抽象的东西具体实现)

举报

相关推荐

0 条评论