区间重叠

给定一个源区间【x,y】(y>=x) 和N个 无序的目标区间[x1,y1] [x2,y2] ....[xn,yn] 判断源区间[x,y]是不是在目标区间内


方法1:

一个直接的思路即将源区间[x,y]和N个无序的目标区间逐个投影到坐标轴上 只考察源区间未被覆盖的部分 如果所有的目标区间全部投影完毕 仍有源区间没有被覆盖 那么源区间就不在目标区间之间


方法2:


对现有的数组进行一些预处理(如合并 排序) 将无序的目标区间合并成几个有序的区间 这样就可以进行区间的比较 


首先可以做一次数据初始化的工作由于目标区间是无序的 可以对其进行合并操作 使其变得有序 先将目标区间数组按X轴坐标从小到大排序 然后扫描数组 将这些区间合并成诺干个不相交的区间  因为区间下标 按照升序排列 运用二分查找的方法 来判断源区间[x y]是否被合并后的这些互不相交的区间的某一个包含

排序的时间复杂度为:O(N*logN) (N为目标区间个数)

合并的时间复杂度为O(N)

单次查找的时间复杂度为O(log2N)

总的时间复杂度为 O (NlogN +k*logN) k为查询的次数 合并目标区间数组的初始化数据操作只需要进行一次


typedef struct point{
	int x;
	int y;
};
int cmp( const void *a , const void *b )
{
	return (*(point *)a).x>(*(point *)b).x?1:-1;
}
void merges(point *p,int n,point *d,int *k)
{
	int *t=new int[2*n];
	for(int i=0;i<n;i++)
	{
		t[2*i]=p[i].x;
		t[2*i+1]=p[i].y;
	}
	int flag=0;
	for(int i=0,j=i+2;i<2*n-flag;i=i+2)
	{
		int tmp=i+1;
		j=tmp+1;
		while(1)
		{
		if(t[tmp]>=t[j])
		{
			t[tmp]=t[j]=-1;
			flag=flag+2;
			tmp=tmp-1;
			j=j+1;
		}
		else
			break;
		}
	}
	int tt=0;
	for(int i=0;i<2*n;)
	{
		if(t[i]!=-1 )
			d[tt].x=t[i];
		i++;
		while( t[i]==-1)
			i++;
		d[tt].y=t[i];
		i++;
		(tt)++;
	}

	*k=tt;
	delete []t;

}
int find(point *p,int k,int m)
{
	int l=0,r=k;
	while (l<=r)
	{
		int mid=(l+r)>>1;
		if( m >= p[mid].x)
			l=mid+1;
		else
			r=mid-1;
	}
	return r;

}
int main() {
	int n=4;
	int *a=new int [n];//对应 x1, x2, ... , xn
	int *b=new int [n];//对应 y1, y2, ... ,yn
	point *p1=new point[n];
    point *p2=new point[n];
	a[0]=1;
	a[1]=5;
	a[2]=2;
	a[3]=10;
	b[0]=3;
	b[1]=9;
	b[2]=4;
	b[3]=11;
	p1[0].x=1;
	p1[1].x=5;
	p1[2].x=2;
	p1[3].x=8;
	p1[0].y=3;
	p1[1].y=9;
	p1[2].y=4;
	p1[3].y=11;
	int x=2;
	int y=10;
	qsort(p1,4,sizeof(p1[0]),cmp);
	int k=0;
	merges(p1,n,p2,&k);
	int s1= find(p2,k,x);
	int s2=find(p2,k,y);
	if(s1==s2 )
		cout<<"true"<<endl;
	else
		cout<<"false"<<endl;
	delete []a;
	delete []b;
	delete[]p1;
	delete []p2;
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值