一,问题:
1. 给定一个源区间[x,y]和N个无序的目标区间[x1,y1] [x2,y2] … [xn,yn],判断源区间[x,y]是不是在目标区间内。
2. 给定一个窗口区域和系统界面上的N个窗口,判断这个窗口区域是否被已有的窗口覆盖。
方法一:编程之美的解法,首先利用快排将区间按照从小到大排序,[2,3][1,2][3,9]-》[1,2][2,3][3,9];然后对排序的区间进行合并;合并后运用二分法查找。
#include <iostream>
#include <algorithm>
using namespace std;
struct Line{
int low,high;
Line(int l=0,int h=0):low(l),high(h){}
bool operator<(Line & other)
{
return low<other.low;
}
};
const int MAX = 100;
Line lines[MAX];
//注意咱们搜索的数为刚好小于key的那个值
int BinarySearchLower(Line arr[],int len,int target)
{
int low = 0;
int high = len-1;
while(low < high){
int mid = (low + high)/2;
if(arr[mid].low>=target)high = mid-1;
else low = mid + 1;
}
return high;
}
int main()
{
int n, k, i, j;
cin>>n; // n是目标区间的个数,k是待查询的源区间的个数
for (i=0; i<n; i++)
cin >> lines[i].low >> lines[i].high;
sort(lines, lines+n);
int cnt = 0; //合并以后的区间数
int lasthigh = lines[0].high;
//合并区间
for(i=1; i<n; i++){
if(lasthigh>=lines[i].low && lasthigh<lines[i].high)
lasthigh = lines[i].high;
else{
lines[cnt].high = lasthigh;
lines[++cnt].low = lines[i].low;
lasthigh = lines[i].high;
}
}
lines[cnt++].high = lasthigh;
Line search = Line(1,6);
int sLow = BinarySearchLower(lines,cnt,search.low);
int sHigh = BinarySearchLower(lines,cnt,search.high);
if(sLow==sHigh && search.high<=lines[sLow].high)//注意要判断
cout<<"Yes"<<endl;
else cout<<"No"<<endl;
system("pause");
return 0;
}
方法二:并查集
#include <iostream>
using namespace std;
const int size = 100;
int faher[size];
//我们用正负区分根节点
//负表示根节点,负数表示集合中的个数
//正数表示子节点,father[i]表示父亲的索引
void MakeSet(int len)//-1表示集合中的个数为1
{
for(int i=0; i<len; i++){
faher[i] = -1;//初识化,大家独自一个集体
}
}
int Find(int x)
{
if(faher[x]>=0)
return Find(faher[x]);
else
return x;
}
void Union(int x,int y)
{
int xRoot = Find(x);
int yRoot = Find(y);
int temp;
if(xRoot != yRoot){
temp = faher[xRoot] + faher[yRoot];
if(faher[xRoot]<faher[yRoot]){//说明x的子节点多余y的子节点,避免生产退化树
faher[xRoot] = temp;
faher[yRoot] = xRoot;
}else{
faher[yRoot] = temp;
faher[xRoot] = yRoot;
}
}
}
void PrintSet(int len)
{
cout<<"Set:";
for(int i=0; i<len; i++)
cout<<faher[i]<<" ";
cout<<endl;
}
int main()
{
int n;
cin>>n; //区间的个数
MakeSet(20);
PrintSet(20);
while(n--){
int x,y;
cin>>x>>y; //输入每个区间
if(x>y){//这一步很关键,表示考虑的周到
swap(x, y);
}
for(int i=x+1; i<=y; i++){//将区间内的 段合并到已有区间
Union(x,i);
}
PrintSet(20);
}
int x1, y1;
cin>>x1>>y1;//输入要判断区间
if(Find(x1) == Find(y1)){
cout<<"yes"<<endl;
}
else{
cout<<"no"<<endl;
}
system("pause");
return 0;
}
这里贴一道百度的题目:题目描述:请编写程序,找出下面“输入数据及格式”中所描述的输入数据文件中最大重叠区间的大小。对一个正整数n,如果n在数据文件中某行的两个正整数(假设为A和B)之间,即A<=n<=B或A>=n>=B,则n属于该行;如果n同时属于行i和j,则i和j有重叠区间;重叠区间的大小是同时属于行i和j的整数个数。
例如,行(10 20)和(12 25)的重叠区间为[12 20],其大小为9;行(20 10)和(12 18)的重叠区间为[10 12],其大小为3;行(20 10)和(20 30)的重叠区间大小为1。
答案:解法1先排序+判断重复的区间http://www.cnblogs.com/absolute8511/archive/2009/05/13/1649584.html
解法2:用位图,int bitmap[len],对将每个区间写入位图,位图相应位置加1操作,bitmap[pos]++,最后统计大于的区域且连续的区域的长度最大值。就向下图所示,区域的计数为1表示有但是没有重叠,0表示该区间没有被覆盖到,2表示有个区间覆盖到,3表示有3个区间覆盖到,4表示有4个区间覆盖到。我们只有判断大于1区域长度的最大值,下图中明显为4区域。
________________________________________________________________________
|______1_____|______2______|____3____|____0____|_______4_________________|
解法3:线段树。