Find Right Interval(寻找右区间)

题目来源
给出一个区间数组,要求其中每个区间的最邻近右区间。如果存在,则返回最邻近右区间在数组中的下标;如果不存在,则返回-1。区间A的最邻近右区间B定义为,区间B的左边界大于或等于区间A的右边界,并且区间B是该区间数组所有满足条件的区间中左边界最小的区间。
题目保证所有区间的右区间大于或等于其左区间,并且所有区间的左区间都互不相同。
例如:
Input: [ [1,2] ]
Output: [-1]
Explanation: There is only one interval in the collection, so it outputs -1.
Input: [ [3,4], [2,3], [1,2] ]
Output: [-1, 0, 1]
Explanation: There is no satisfied "right" interval for [3,4].
For [2,3], the interval [3,4] has minimum-"right" start point;
For [1,2], the interval [2,3] has minimum-"right" start point.
Input: [ [1,4], [2,3], [3,4] ]
Output: [-1, 2, -1]
Explanation: There is no satisfied "right" interval for [1,4] and [3,4].
For [2,3], the interval [3,4] has minimum-"right" start point.

---------------------------
一种显而易见的解法是使用两重循环。对于输入区间数组中的每一个区间,都遍历一遍区间数组,尝试寻找一个满足条件的最邻近右区间。这种解法的时间复杂度为O(n^2),空间复杂度为O(1)。

尝试对上述解法的时间复杂度进行优化。由于对于每个区间都要寻找一个其左边界大于当前区间右边界并且在所有区间中左边界最小的区间,一种比较自然的想法是考虑将输入区间数组按照区间的右边界升序排序,从而可以使用二分查找来优化寻找操作的时间复杂度。为了在排序之后仍然能够保留各个区间在数组的位置信息,用一个HashMap来保存并快速索引下标信息,同时备份输入数组。根据这样的思路,原理性的代码如下:

public int[] findRightInterval(Interval[] intervals) {
	Interval[] sortedInterval = Arrays.copyOf(intervals, intervals.length);
	Arrays.sort(sortedInterval, (a, b) -> { return (a.start - b.start);});
	Map<Interval, Integer> map = new HashMap<>();
	for(int i = 0; i < intervals.length; i++) {
		map.put(intervals[i], i);
	}
	   
	int[] result = new int[intervals.length];
	for(int i = 0; i < intervals.length; i++) {
		int target = intervals[i].end, rs = -1;
		int lt = 0, rt = intervals.length - 1, mid = 0;
		while(lt <= rt) {
			mid = (lt + rt) / 2;
			if(sortedInterval[mid].start < target) {
				lt = mid + 1;
			} else if(mid == 0 || sortedInterval[mid - 1].start < target) {
				rs = map.get(sortedInterval[mid]);
				break;
			} else {
				rt = mid - 1;
			}
		}
		result[i] = rs;
	}
	  
	return result;
}
可以充分利用Java类库提供的功能,将上述代码进行简化而得到更加优雅的代码,如下所示:

public int[] findRightInterval(Interval[] intervals) {
	int[] result = new int[intervals.length];
	NavigableMap<Integer, Integer> intervalMap = new TreeMap<>();
	for (int i = 0; i < intervals.length; ++i) {
		intervalMap.put(intervals[i].start, i);    
	}
	
	for (int i = 0; i < intervals.length; ++i) {
		Map.Entry<Integer, Integer> entry = intervalMap.ceilingEntry(intervals[i].end);
		result[i] = (entry != null) ? entry.getValue() : -1;
	}
        
	return result;
}
这种解法的时间复杂度为O(nlogn),空间复杂度为O(n)。对比第一种解法,空间复杂度由O(1)增加为O(n),带来的好处是时间复杂度由O(n^2)减小为O(nlogn)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值