[LeetCode] 436. Find Right Interval
You are given an array of intervals
, where intervals[i] = [starti, endi]
and each starti
is unique.
The right interval for an interval i
is an interval j
such that startj >= endi
and startj
is minimized. Note that i
may equal j
.
Return an array of right interval indices for each interval i
. If no right interval exists for interval i
, then put -1
at index i
.
Example 1:
Input: intervals = [[1,2]] Output: [-1] Explanation: There is only one interval in the collection, so it outputs -1.
Example 2:
Input: intervals = [[3,4],[2,3],[1,2]] Output: [-1,0,1] Explanation: There is no right interval for [3,4]. The right interval for [2,3] is [3,4] since start0 = 3 is the smallest start that is >= end1 = 3. The right interval for [1,2] is [2,3] since start1 = 2 is the smallest start that is >= end2 = 2.
Example 3:
Input: intervals = [[1,4],[2,3],[3,4]] Output: [-1,2,-1] Explanation: There is no right interval for [1,4] and [3,4]. The right interval for [2,3] is [3,4] since start2 = 3 is the smallest start that is >= end1 = 3.
Constraints:
1 <= intervals.length <= 2 * 104
intervals[i].length == 2
-106 <= starti <= endi <= 106
- The start point of each interval is unique.
寻找右区间。
给你一个区间数组 intervals ,其中 intervals[i] = [starti, endi] ,且每个 starti 都 不同 。
区间 i 的 右侧区间 可以记作区间 j ,并满足 startj >= endi ,且 startj 最小化 。
返回一个由每个区间 i 的 右侧区间 的最小起始位置组成的数组。如果某个区间 i 不存在对应的 右侧区间 ,则下标 i 处的值设为 -1 。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/find-right-interval
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题意是给一个 list,里面装的是一些 interval 区间,对于每个 interval i,请你寻找是否存在另外一个 interval j,满足 j 在 i 的右边。在右边的定义是 j 的起点要大于等于 i 的终点。对于每一个 interval i,如果能找到一个这样的 j 区间,则返回 j 的下标,否则返回-1。
这道题有两种做法,一种是treemap,一种是二分法。
首先介绍 treemap 的做法。遍历 input,将每个区间的起点当做 key,每个区间的下标当做 value 放入 treemap。再次遍历 input,此时会利用到 treemap 的一个函数叫做ceilingKey(),找当前 map 中是否存在一个最小的区间的起点,这个起点比当前遍历到的区间的终点要大。如果找到,则放入结果集。
时间O(nlogn) - treemap search
空间O(n)
Java实现
1 class Solution { 2 public int[] findRightInterval(int[][] intervals) { 3 int[] res = new int[intervals.length]; 4 TreeMap<Integer, Integer> map = new TreeMap<>(); 5 for (int i = 0; i < intervals.length; i++) { 6 map.put(intervals[i][0], i); 7 } 8 9 for (int i = 0; i < intervals.length; i++) { 10 Integer key = map.ceilingKey(intervals[i][1]); 11 res[i] = key != null ? map.get(key) : -1; 12 } 13 return res; 14 } 15 }
二分法稍微复杂一点。所有做二分的题目,二分的前提是被二分查找的数组应该是有序的,但是这道题我们不能对 input 数组进行排序。这里我们需要额外使用一个数组 arr,记录每个区间的起点,我们还需要一个hashmap,记录每个区间的<起点,下标>对应关系。我参考了这个帖子。
我们先遍历一遍 input 数组,把数据预处理一下,arr 记录了每个区间的起点,hashmap 记录了每个子区间的起点和下标。接着我们开始遍历每个子区间,对于每个子区间的终点 end,我们要去 arr 数组里找一个大于 end 的最小的起点。因为 arr 数组此时已经是有序的了,所以这里可以用二分。如果找不到这个起点就返回 -1,如果能找到这个起点的话,那么我们再去 hashmap 里找出这个起点对应的下标 i 即可,存入结果集。
时间:排序O(nlogn), 预处理O(n), 二分O(logn) = O(nlogn)
空间O(n) - hashmap 和 arr 数组
Java实现
1 class Solution { 2 public int[] findRightInterval(int[][] intervals) { 3 int len = intervals.length; 4 HashMap<Integer, Integer> map = new HashMap<>(); 5 // arr存的是每个interval的start 6 int[] arr = new int[len]; 7 int[] res = new int[len]; 8 for (int i = 0; i < len; i++) { 9 map.put(intervals[i][0], i); 10 arr[i] = intervals[i][0]; 11 } 12 13 Arrays.sort(arr); 14 for (int i = 0; i < len; i++) { 15 int index = binarySearch(arr, intervals[i][1]); 16 if (index == -1) { 17 res[i] = -1; 18 } else { 19 res[i] = map.get(arr[index]); 20 } 21 } 22 return res; 23 } 24 25 private int binarySearch(int[] arr, int target) { 26 int len = arr.length; 27 // corner case 28 if (arr[len - 1] < target) { 29 return -1; 30 } 31 32 int left = 0; 33 int right = len - 1; 34 while (left < right) { 35 int mid = left + (right - left) / 2; 36 if (arr[mid] < target) { 37 left = mid + 1; 38 } else { 39 right = mid; 40 } 41 } 42 return left; 43 } 44 }