问题描述:
给定一个源区间[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;
}