重合区间最长的两个区间段SegmentOverlap

在一维坐标轴上有n个区间段,求重合区间最长的两个区间段。【问题来源于v_JULY_v的博客:http://blog.csdn.net/v_july_v/article/details/6803368

第一部分:思路

1. 对N个区间排序,排序的规则为:先按区间的开始点从小到大排,若开始点相同,则再按结束点排

例如:对于区间[1,3],[2,3],[1,4]排序后的结果是:[1,3],[1,4],[2,3]

2. 采用分而治之的策略,将N个区间分为2个N/2的子问题,则N个区间的重合区间最长的2个区间段,比是以下3种中的一个:

1)是前N/2个区间中重合区间最长的

2)是后N/2个区间中重合区间最长的

3)是前N/2个区间中结束点最大的区间,与后N/2个区间中重合最长的区间

因此有递归式:T(n) = 2*T(n/2) + O(n)

/*
*求系列区间中重合最长的两个区间SegmentOverlap
*@author arhaiyun
*Date:2013-09-29
*
*/

class Segment {
	int start;
	int end;
	Segment(int start, int end)
	{
		this.start = start;
		this.end = end;
	}
}
public class SegmentOverlap {
	private SegmentOverlap() {}
	/**
	 * 快速排序:对N个区间进行排序,排序的规则为:先按区间的开始点从小到大排,
	 * 若开始点相同,则再按结束点排 
	 */
	static void quicksort(Segment[] set, int left, int right)
	{
		if(left<right)
		{
			int mid = partition(set, left, right);
			quicksort(set, left, mid-1);
			quicksort(set, mid+1, right);
		}
	}
	static int partition(Segment[] set, int left, int right)
	{
		int start = left, end = right;
		left++;
		Segment tmp = null;
		while(left<=right)
		{
			while(left <= right && compare(set[left],set[start])<=0)
			{
				left++;
			}
			while(left <= right && compare(set[right],set[start])>0)
			{
				right--;
			}
			if(left<right)
			{
				tmp = set[left];
				set[left] = set[right];
				set[right] = tmp;
			}
		}
		tmp = set[right];
		set[right] = set[start];
		set[start] = tmp;
		return right;
	}
	static int compare(Segment s1, Segment s2)
	{
		if(s1.start<s2.start||(s1.start==s2.start&&s1.end<s2.end))
		{
			return -1;
		}else if(s1.start==s2.start&&s1.end==s2.end)
		{
			return 0;
		}else
		{
			return 1;
		}
	}
	
	/**
	 * 递归求解
	 */
	static Segment[] overlap(Segment[] set, int left, int right)
	{
		Segment[] ret = null;
		if(left<right)
		{
			ret = new Segment[2];
			//往前找结束点最大的
			int mid = (left + right) >> 1;
			ret[0] = set[mid];
			for(int i=mid-1;i>=left;i--)
			{
				if(set[i].end>ret[0].end)
				{
					ret[0] = set[i];
				}
			}
			//往后找出重合区间最大的
			int maxlen = -1, curlen = -1;
			ret[1] = set[mid+1];
			maxlen = getLen(ret[0],ret[1]);
			for(int j=mid+2;j<=right;j++)
			{
				curlen = getLen(ret[0],set[j]);
				if(curlen==0)
				{
					break;
				}
				if(curlen>maxlen)
				{
					maxlen = curlen;
					ret[1] = set[j];
				}
			}
			
			//前N/2个区间
			Segment[] leftmax = overlap(set, left, mid);
			if(leftmax!=null&&(curlen=getLen(leftmax[0],leftmax[1]))>maxlen)
			{
				maxlen = curlen;
				ret = leftmax;
			}
			//后N/2个区间
			Segment[] rightmax = overlap(set, mid+1, right);
			if(rightmax!=null&&(curlen=getLen(rightmax[0], rightmax[1]))>maxlen)
			{
				maxlen = curlen;
				ret = rightmax;
			}
		}
		return ret;
	}
	/**
	 * 返回2个区间重合的长度,其中第一个区间的开始点不晚于第二个区间的开始点
	 */
	static int getLen(Segment s1, Segment s2)
	{
		int x = s1.start >= s2.start ? s1.start : s2.start;
		int y = s1.end <= s2.end ? s1.end : s2.end;
		int len = y - x;
		return len>0? len:0;
	}
	
	/**
	 * 对外接口,返回重合区间最长的2个区间
	 * @param set
	 * 		区间的集合
	 * @param len
	 * 		集合的长度
	 * @return
	 * 		重合区间最长的2个区间
	 */
	public static Segment[] find(Segment[] set, int len)
	{
		quicksort(set,0,len-1);
		return overlap(set,0,len-1);
	}
	
	public static void main(String[] args)
	{
		//....
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值