区间重合判断

本文介绍了《编程之美》中2.19节的区间重合判断问题的解决方案。通过排序、合并重合区间以及使用二分查找法,确定源区间是否在目标区间内。具体实现包括对目标区间排序、合并后进行二分查找,判断源区间的边界是否在同一合并后区间内。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

《编程之美》第2.19节:区间重合判断

问题:给定一个源区间[x,y](y>=x)和N个无序的目标区间[x1,y1]…[xn,yn],判断源区间[x,y]是不是在目标区间内?

解法:将目标区间排序,然后合并重合区间,最后用二分法查看源区间是否在目标区间内。

代码:

<span style="font-size:14px;">#include<iostream>
#include<list>
#include<algorithm>
using namespace std;

struct Node
{
	int begin;
	int end;
	Node(int b=0,int e=0):begin(b),end(e){}
	bool operator<(const Node &node)const 
	{return begin==node.begin?end<node.end:begin<node.begin;}
};

bool segmentIncluded(list<Node> L,const Node &node)
{
	L.sort();
	list<Node>::iterator iter=L.begin();
	list<Node>::iterator temp=L.begin();
	for(++iter;iter!=L.end();)
	{
		if(temp->end>=iter->begin)
		{
			temp->end=iter->end;
			iter=L.erase(iter);
		}
		else
		{
			temp=iter;
			++iter;
		}
	}
	for(iter=L.begin();iter!=L.end();++iter)
	{
		if(iter->begin<=node.begin && iter->end>=node.end)
			return true;
	}
	return false;
}

int main()
{
	list<Node> L;
	L.push_back(Node(2,3));
	L.push_back(Node(1,2));
	L.push_back(Node(3,9));
	bool result=segmentIncluded(L,Node(1,6));
	cout<<result<<endl;

	system("pause");
	return 0;
}</span>
一下转自:http://blog.youkuaiyun.com/tianshuai1111/article/details/7828961解法比较巧妙

 先用区间的左边界值对目标区间进行排序O(nlogn),对排好序的区间进行合并O(n),对每次待查找的源区间,用二分查出其左右两边界点分别处于合并后的哪个源区间中O(logn),若属于同一个源区间则说明其在目标区间中,否则就说明不在。

注意:下面这个代码GetIndex函数查找的是小于key的与key最接近的下标值,先找出与源区间[low,high]中low最接近的起始点,然后找到与high最接近的起始点,这两个起始点应该是一个点,否则[low,high]区间就不在目标区间内。

[html] view plaincopy
  1. #include <iostream>  
  2. #include <algorithm>  
  3. using namespace std;  
  4.   
  5. struct Line  
  6. {  
  7.     int low, high;  
  8.     bool operator<(const Line &l) const  
  9.     {return low<l.low;}  
  10. };  
  11.   
  12. #define MAXN 10001  
  13. Line lines[MAXN];   // 目标区间  
  14. int ncnt = 0;       // 合并后区间的个数  
  15.   
  16. #define N 101  
  17. Line sl[N];         // 待查询的源区间  
  18.   
  19. // 用二分查找找出key所在的区间,以区间的low作为划分  
  20. int GetIndex(int key)  
  21. {  
  22.     int u, v;  
  23.     u = 0v = ncnt-1;  
  24.     while (u<=v) // u,v可取等号  
  25.     {  
  26.         int m = (u+v)>>1;  
  27.         if (key >= lines[m].low)  
  28.             u = m+1;  
  29.         else  
  30.             v = m-1;  
  31.     }  
  32.     return v;  
  33. }  
  34.   
  35. int main()  
  36. {  
  37.     int n, k, i, j;  
  38.     cin >> n >> k;  // n是目标区间的个数,k是待查询的源区间的个数  
  39.     for (i=0; i<n; i++)  
  40.         cin >> lines[i].low >> lines[i].high;  
  41.     for (i=0; i<k; i++)  
  42.         cin >> sl[i].low >> sl[i].high;  
  43.     // 排序O(nlogn)  
  44.     sort(lines, lines+n);  
  45.     // 合并O(n)  
  46.     int lasthigh = lines[0].high;  
  47.     for (i=1; i<n; i++)  
  48.         if (lasthigh >= lines[i].low)  
  49.             lasthigh = lines[i].high;  
  50.         else  
  51.         {  
  52.             lines[ncnt++].high = lasthigh;  
  53.             lines[ncnt].low = lines[i].low;  
  54.             lasthigh = lines[i].high;  
  55.         }  
  56.     lines[ncnt++].high = lasthigh;  
  57.     for (i=0; i<k; i++)  
  58.     {  
  59.         // 单词查找时间O(logn)  
  60.         int s1 = GetIndex(sl[i].low);  
  61.         int s2 = GetIndex(sl[i].high);  
  62.         if (s1==s2 && sl[i].high <= lines[s2].high)  
  63.             printf("Yes\n");  
  64.         else  
  65.             printf("No\n");  
  66.     }  
  67. }  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值