编程之美——区间重合判断
一. 问题:
1. 给定一个源区间[x,y]和N个无序的目标区间[x1,y1] [x2,y2] ... [xn,yn],判断源区间[x,y]是不是在目标区间内。
2. 给定一个窗口区域和系统界面上的N个窗口,判断这个窗口区域是否被已有的窗口覆盖。
二. 解法:
问题一:先用区间的左边界值对目标区间进行排序O(nlogn),对排好序的区间进行合并O(n),对每次待查找的源区间,用二分查出其左右两边界点分别处于合并后的哪个源区间中O(logn),若属于同一个源区间则说明其在目标区间中,否则就说明不在。
代码为:
#include<iostream>
#include<algorithm>
using namespace std;
struct Line
{
int low,high;
bool operator<(const Line &l) const
{
return low<l.low;
}
};
#define MAXN 10001
Line lines[MAXN];
int ncnt=0;
#define N 101
Line s1[N];
int GetIndex(int key)
{
int u,v;
u=0;
v=ncnt-1;
while(u<=v)
{
int m=(u+v)/2;
if(key>=lines[m].low)
u=m+1;
else
v=m-1;
}
return v;
}
int main()
{
int n,k,i,j;
cin>>n>>k;
for(i=0;i<n;i++)
cin>>lines[i].low>>lines[i].high;
for(i=0;i<k;i++)
cin>>s1[i].low>>s1[i].high;
//排序O(nlogn)
sort(lines,lines+n);
//合并O(n)
int lasthigh=lines[0].high;
for(int i=1;i<n;i++)
{
if(lasthigh>=lines[i].low)
lasthigh=lines[i].high;
else
{
lines[ncnt++].high=lasthigh;
lines[ncnt].low=lines[i].low;
lasthigh=lines[i].high;
}
}
lines[ncnt++].high=lasthigh;
for(i=0;i<k;i++)
{
int s1=GetIndex(s1[i].low);
int s2=GetIndex(s1[i].high);
if(s1==s2 && s1[i].high<=lines[s2].high)
{
cout<<"yes";
}
else
{
cout<<"No";
}
}
}
#include<algorithm>
using namespace std;
struct Line
{
int low,high;
bool operator<(const Line &l) const
{
return low<l.low;
}
};
#define MAXN 10001
Line lines[MAXN];
int ncnt=0;
#define N 101
Line s1[N];
int GetIndex(int key)
{
int u,v;
u=0;
v=ncnt-1;
while(u<=v)
{
int m=(u+v)/2;
if(key>=lines[m].low)
u=m+1;
else
v=m-1;
}
return v;
}
int main()
{
int n,k,i,j;
cin>>n>>k;
for(i=0;i<n;i++)
cin>>lines[i].low>>lines[i].high;
for(i=0;i<k;i++)
cin>>s1[i].low>>s1[i].high;
//排序O(nlogn)
sort(lines,lines+n);
//合并O(n)
int lasthigh=lines[0].high;
for(int i=1;i<n;i++)
{
if(lasthigh>=lines[i].low)
lasthigh=lines[i].high;
else
{
lines[ncnt++].high=lasthigh;
lines[ncnt].low=lines[i].low;
lasthigh=lines[i].high;
}
}
lines[ncnt++].high=lasthigh;
for(i=0;i<k;i++)
{
int s1=GetIndex(s1[i].low);
int s2=GetIndex(s1[i].high);
if(s1==s2 && s1[i].high<=lines[s2].high)
{
cout<<"yes";
}
else
{
cout<<"No";
}
}
}
问题二解法:
这个问题适合使用线段树来解答,单次查找的时间复杂度为O(nlogn),当然也能用数组解答,但单次查找的时间复杂度会增加到O(n^2)。这里我们直接使用线段树来解答。
线段树是一棵二叉树,将数轴划分成一系列的初等区间[I, I+1] (I=1,2,..,N-1)。每个初等区间对应于线段树的一个叶结点。线段树的内部结点对应于形如[ I, J ](J – I > 1)的一般区间。由于线段树给每一个区间都分配了结点,利用线段树可以求区间并后的总长度与区间并后的线段数。先给出测试数据(前4行是系统界面上已有的N个窗口,之后的一行是待测试的窗口区域),后面是代码:
4
-15 0 5 10
-5 8 20 25
15 -4 24 14
0 -6 16 4
2 15 10 22
代码为:
参考:http://blog.csdn.net/tianshuai11/article/details/7828961