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.
如果做过前面类似的有关intervals的题目,那么做这一题就比较简单的,很容易想到先排序,再遍历完成。
思路:
首先,根据题意要求,最后是要输出的是对应的interval的index,所以需要新构造一个数组int[][3]={start,end,index}(实际上end是不需要存储的,也不需要参与排序,在后面的代码2中可以看到这一点),前两个参数就是原来的开始和结束,第三个参数保存的是原来的该interval的位置(当然你构造一个类也可以,但是new大量的类的效率就会大打折扣)。
接下来,按照start升序排序,相同的start按照index升序排序(非常关键)。
然后,新建一个结果数组int[] result。遍历整个数组,找到当前元素(current)的end,然后使用循环找到后面的第一个new.start>=current.end的元素(new),将该元素的index值(new.index)写在当前result的对应位置,result[current.index]=new.index;如果循环结束都没有找到,result[current.index]=-1;以此类推,直到遍历完所有的元素,返回result即可。(如果使用数组的话,上面的start end index 分布为int[0] int[1] int[2])
代码如下,复杂度大约是O(nlogn)+O(n^2),事实上,是不可能达到理论上界的,因为第二项其实应该是个较大系数的O(n),所以猜测真实时间要稍稍大于nlogn的数量级,在nlogn和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; }
* }
*/
public class Solution {
public int[] findRightInterval(Interval[] intervals) {
int[] nResults = new int[intervals.length];
// init results array
for (int i = 0; i < nResults.length; i++) {
nResults[i] = -1;
}
// init intervals array
int[][] nIntervalsWithIndex = new int[intervals.length][3];
for (int i = 0; i < nIntervalsWithIndex.length; i++) {
nIntervalsWithIndex[i][0] = intervals[i].start;
nIntervalsWithIndex[i][1] = intervals[i].end;
nIntervalsWithIndex[i][2] = i;
}
Arrays.sort(nIntervalsWithIndex, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
if (o1[0] == o2[0]) {
return o1[2] - o2[2];
} else {
return o1[0] - o2[0];
}
}
});
for (int i = 0; i < nIntervalsWithIndex.length; i++) {
int nOriIndex = nIntervalsWithIndex[i][2];
int nCurEnd = nIntervalsWithIndex[i][1];
int nCurIndex = i;
while (nCurIndex + 1 < nIntervalsWithIndex.length) {
nCurIndex++;
if (nIntervalsWithIndex[nCurIndex][0] >= nCurEnd) {
nResults[nOriIndex] = nIntervalsWithIndex[nCurIndex][2];
break;
}
}
}
return nResults;
}
}
事实上,在上面的内存循环中,我们遍历了当前元素后面的元素。由于该内容其实是已经排好序的,而且我们只需要找到指定元素,这里显然是可以优化的,比如:可以考虑使用二分查找。因此,我们可以使用treeMap来存储数据,它默认按照key排序排列,而且treeMap的检索效率为O(logn)。
代码如下,新的代码复杂度为O(nlogn),实际时间消耗大约为2nlogn:
/**
* 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; }
* }
*/
import java.util.Map.Entry;
public class Solution {
public int[] findRightInterval(Interval[] intervals) {
int[] nResults = new int[intervals.length];
TreeMap<Integer, Integer> tm = new TreeMap<>();
for (int i = 0; i < intervals.length; i++) {
tm.put(intervals[i].start, i);
}
for (int i = 0; i < intervals.length; i++) {
Entry<Integer, Integer> e = tm.ceilingEntry(intervals[i].end);
nResults[i] = e == null ? -1 : e.getValue();
}
return nResults;
}
}
代码如下,复杂度大约是O(nlogn)+O(n^2),事实上,是不可能达到理论上界的,因为第二项其实应该是个较大系数的O(n),所有猜测真实时间稍大于nlogn: