编程之美区间重合判断

一,问题:

    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:线段树。

    原文作者:继续微笑lsj
    原文地址: https://blog.csdn.net/lsjseu/article/details/11830127
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞