问题:
Given a set of intervals, for each of the interval i, check if there exists an interval j whose start point is bigger than or equal to the end point of the interval i, which can be called that j is on the "right" of i.
For any interval i, you need to store the minimum interval j's index, which means that the interval j has the minimum start point to build the "right" relationship for interval i. If the interval j doesn't exist, store -1 for the interval i. Finally, you need output the stored value of each interval as an array.
Note:
- You may assume the interval's end point is always bigger than its start point.
- You may assume none of these intervals have the same start point.
Example 1:
Input: [ [1,2] ] Output: [-1] Explanation: There is only one interval in the collection, so it outputs -1.
Example 2:
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.
Example 3:
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.
解决:
① 要求找到start比区间i的end大或相等的一个区间。使用map记录interval及其下标,对interval进行排序,然后查找符合条件的值即可。暴力破解,O(N^2)。
/**
* Definition for an interval.
* public class Interval {
* int start;
* int end;
* Interval() { start = 0; end = 0; }
* Interval(int s, int e) { start = s; end = e; }
* }
*/
class Solution { //215ms
public int[] findRightInterval(Interval[] intervals) {
int len = intervals.length;
int[] res = new int[len];
Arrays.fill(res,-1);
Map<Interval,Integer> map = new HashMap<>();
int i = 0;
for (Interval interval : intervals){
map.put(interval,i);
i ++;
}
Interval[] tmp = intervals.clone();
Arrays.sort(tmp, new Comparator<Interval>() {
@Override
public int compare(Interval o1, Interval o2) {
return o1.start - o2.start;
}
});
for (i = 0;i < len - 1;i ++){//在查找方面,可以使用二分查找进行优化,时间复杂度O(nlogn)。
for (int j = i + 1;j < len;j ++){
if (tmp[i].end <= tmp[j].start){
res[map.get(tmp[i])] = map.get(tmp[j]);
break;
}
}
}
return res;
}
}
② 使用TreeMap定义的接口。
treemap自带接口方法lowerEntry、floorEntry、ceilingEntry和higherEntry分别返回与小于、小于等于、大于等于、大于给定键的键关联的Map.Entry对象,如果不存在这样的键,则返回null。类似地,方法lowerKey、floorKey、ceilingKey和higherKey只返回关联的键。
class Solution { //54ms
public int[] findRightInterval(Interval[] intervals) {
int len = intervals.length;
int[] res = new int[len];
TreeMap<Integer,Integer> map = new TreeMap<>();
for (int i = 0;i < len;i ++){
map.put(intervals[i].start,i);//建立interval的start与下标之间的映射关系
}
for (int i = 0;i < intervals.length;i ++){
Map.Entry<Integer,Integer> entry = map.ceilingEntry(intervals[i].end);//找到满足所有key大于等于当前interval的end的interval
res[i] = (entry != null) ? entry.getValue() : -1;
}
return res;
}
}
③ 在discuss看到的。将interval映射为有序的一维数组。
class Solution { //7ms
//此种做法其实并不难!!!关键是我们要把这些interval放在一个一维数组上来考虑
public int[] findRightInterval(Interval[] intervals) {
int max = Integer.MIN_VALUE;//标识最大的end
int min = Integer.MAX_VALUE;//标识最小的start
for(Interval interval : intervals){
max = Math.max(max, interval.end);
min = Math.min(min, interval.start);
}
//建立bucket, max是end最大值,min是start最小值,画一个1d的坐标轴
int[] start = new int[max - min + 1];
Arrays.fill(start, -1);
for(int i = 0; i < intervals.length; i ++){//根据start将interval映射到一维数组中
//每个bucket的index代表距离0点,intervals[i].start - min的interval的index
start[intervals[i].start - min] = i;
}
for(int i = start.length - 2; i >= 0; i--){
//如果start[i] == -1, 证明没有这种距离的interval 存在,那么最近的一个interval就会是这个interval的下一个以此类推,所以我们需要从后向前循环
//因为如果从前往后,就无法保证都是rightmost的interval了
if(start[i] == -1){
start[i] = start[i + 1];
}
}
int[] result = new int[intervals.length];
//intervals[i].end - min可以得到这个interval i他到原点的距离,start中存了,start为这个距离的interval的index
for(int i = 0; i < result.length; i++){
result[i] = start[intervals[i].end - min];
}
return result;
}
}