思路
TreeMap
根据题目描述,注意几个地方,每个start[i]都不同,而且要求start[j]>=end[i],很容易联想到使用带排序的哈希结构,也就是TreeMap,具体实现为:
- 第一次遍历 intervals,完成TreeMap的构造,key为左端点,value为index位置;
- 第二次遍历 intervals,对每个interval的右端点取ceiling,如果不存在,即为-1,填充在结果集中;
排序 + 二分
为了方便,我们称 intervals 为 its。
对于每个 its[i] 而言,我们需要在所有满足 its[j][0] ⩾ its[i][1] 中找到 its[j][0] 值最小的下标 jj,并将其记为 ans[i]。
对于一个特定的 its[i] 而言,其右端点固定,并且我们只关心目标位置的左端点。
因此我们可以构造一个记录区间左端点的数组 clone,并将其进行排序,同时为了记录每个左端点来自于原序列中的那个下标,还需要额外记录原序列下标,即以 (start,idx) 二元组的形式进行转存,并根据 start 排序。
然后从前往后处理每个 its[i],运用「二分」在 clone 中找到第一个满足左端点 start 大于等于 its[i][1] 的成员 clone[j],将其 clone[j][1] 即是 its[i] 的最右区间。
代码实现(java)
class Solution {
public int[] findRightInterval(int[][] intervals) {
// 排序 + 二分
int n = intervals.length;
int[][] clone = new int[n][2];
for(int i = 0; i < n; i++) {
// 将数组的第一个元素及其下标记录起来
clone[i] = new int[]{intervals[i][0], i};
}
Arrays.sort(clone, (o1, o2) -> o1[0] - o2[0]);
int[] res = new int[n];
for(int i = 0; i < n; i++) {
int l = 0, r = n - 1;
while(l < r) {
int mid = l + (r - l) / 2;
// 找到最左边的边界
if (clone[mid][0] >= intervals[i][1]) r = mid;
else l = mid + 1;
}
// 如果r所在位置的左边界确实大于当前位置的右边界,则取出下标存入res,否则存入-1
res[i] = clone[r][0] >= intervals[i][1] ? clone[r][1] : -1;
}
return res;
// TreeMap方法
// TreeMap<Integer, Integer> map = new TreeMap<>();
// int n = intervals.length;
// for (int i = 0; i < intervals.length; i++) {
// map.put(intervals[i][0], i);
// }
// int[] res = new int[n];
// for(int i = 0; i < n; i++) {
// Integer j = map.ceilingKey(intervals[i][1]);
// if(j == null) res[i] = -1;
// else res[i] = map.get(j);
// }
// return res;
}
}