[编程之美] PSet2.19 区间重合判断

问题描述:

       给定一个源区间[x,y]和N个无序的目标区间[x1,y1] [x2,y2] ... [xn,yn],判断源区间[x,y]是不是在目标区间内。

分析和思路:

       解法一:直接投影法

       直接将源区间和N个无序的目标区间逐个投影在坐标轴上,判断投影完毕后是否仍有元区间没有被覆盖。算法复杂度O(N^2)。代码如下:

//直接法
//将源区间和目标区间统统投影到坐标轴上,最后判断是否仍有源区间没有被覆盖,目标区间可以有多个
struct Interval{
	int left;
	int right;
};
bool findCoincide(const Interval &src , const Interval dst[] , int dstLen)
{
	vector<Interval> srcTemp;
	srcTemp.push_back(src);
	bool flag = false;
	//---将src与dst投影到坐标轴上,看是否仍有src未被覆盖
	for(int i=0 ; i<dstLen ; i++){//遍历所有dst
		for(vector<Interval>::iterator it = srcTemp.begin() ; it!=srcTemp.end() ; ++it){//遍历所有被分割的src
			if(dst[i].left<it->left && it->left<dst[i].right && dst[i].right<=it->right){//情况一
				it->left = dst[i].right;
				if(it->left == it->right)
					it=srcTemp.erase(it);
				break;
			}
			if(it->left<=dst[i].left && dst[i].left<it->right && dst[i].right>it->right){//情况二
				it->right = dst[i].left;
				if(it->left == it->right)
					it=srcTemp.erase(it);
				break;
			}
			if(it->left<=dst[i].left && it->right>=dst[i].right){//情况三
				Interval temp;
				temp.left=dst[i].right;
				temp.right = it->right;
				it->right = dst[i].left;
				if(it->right == it->left){
					it=srcTemp.erase(it);
				}
				if(temp.left != temp.right)
					srcTemp.push_back(temp);
				break;
			}
		}
	}
	if(srcTemp.empty())
		flag = true;
	return flag;
}

       解法二:先排序,合并,最后比较

       考虑将这些无序的数组依左端点大小排序,然后扫描排序后的区间数组,将这些区间合并为若干个不相交的区间。最后运用二分查找判定源空间是否被合并后的空间包含。排序O(NlogN),合并O(N),单次查找复杂度logN,总时间复杂度O(NlogN)+O(N)+K*O(logN) = O(NlogN+KlogN),K为查询次数。

//先排序,后合并空间,最后二分查找
//算法复杂度:O(NlogN+KlogN)
struct Interval{
	int left;
	int right;
	bool operator<(const Interval &src2)const
	{
		return left<src2.left;
	}//用于左端点升序排列
};
bool findCoincide(const Interval src , Interval dst[] , int dstLen)
{

	//---先对目标空间排序O(NlogN)
	sort(dst , dst+dstLen , less<Interval>());
	//---合并排序后空间
	vector<Interval> sortedInterval;
	int preH = dst[0].right;
	int preL = dst[0].left;
	for(int i=1 ; i<dstLen ; i++){
		if(dst[i].left <= preH){//区间相交或相切
			preH = dst[i].right;
		}else{//区间相离
			Interval temp = {preL,preH};
			sortedInterval.push_back(temp);
			preL = dst[i].left;
			preH = dst[i].right;
		}
	}
	Interval temp = {preL,preH};
	sortedInterval.push_back(temp);
	//---二分查找sortedInterval.left<src.left且最接近的sorted.left
	bool flag = false;
	int low = 0;
	int high = sortedInterval.size();
 	while(low <= high){
		int mid = low +(high-low)/2;//防止上溢
		if(sortedInterval[mid].left<=src.left && src.right<=sortedInterval[mid].right){
			flag = true;
			break;;
		}
		else if(src.left < sortedInterval[mid].left)
			high = mid-1;
		else if(src.left > sortedInterval[mid].left)
			low = mid+1;
		else
			break;
	}
	return flag;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值