编程之美——区间重合判断

编程之美——区间重合判断

一. 问题:

       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";
}
  }
}

问题二解法:

      这个问题适合使用线段树来解答,单次查找的时间复杂度为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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值