大家好,我是 @负雪明烛。点击右上方的「+关注,优质题解不间断!

题目大意

需要我这个语文课代表翻译一下今天的题目。

题目给了一个数组 intervals,其中的每个元素都是一个区间,区间的两个值分别是起点和终点。

当区间 B 的起点 大于等于 区间 A 的终点,我们就说区间 B 在区间 A 的右侧。

让我们求每个区间的右侧第一个区间(所有右侧的区间中,起点最小的那个)。

如果还不好理解,请看下面两张图。(为了防止区间的线段相互覆盖,我把区间向上平移了一点)

示例二 intervals = [[3,4],[2,3],[1,2]]

实例三 intervals = [[1,4],[2,3],[3,4]]

解题方法

分析

右侧区间,其起点436. 寻找右区间 - 图1 大于等于 当前区间终点 436. 寻找右区间 - 图2

右侧第一个区间,就是找右侧区间中 436. 寻找右区间 - 图3最小的那个。

题目已经说了每个区间的起点 436. 寻找右区间 - 图4都不会重复。

首先,我们可以把所有区间的起点 436. 寻找右区间 - 图5取出来,这样就成了一个起点的数组 436. 寻找右区间 - 图6

当我们想要寻找一个区间 436. 寻找右区间 - 图7右边的第一个区间时,其实就是求 436. 寻找右区间 - 图8 大于等于 436. 寻找右区间 - 图9的最小值。

怎么找到数组中大于等于 436. 寻找右区间 - 图10的最小值的呢?

最粗暴的方法是遍历,遍历一次的时间复杂度是 436. 寻找右区间 - 图11

对于数组中的每个区间都要遍历一遍,因此总时间复杂度是 436. 寻找右区间 - 图12。题目给出的数据规模是 436. 寻找右区间 - 图13,会超时。

怎么办?

可以使用「二分查找」。

二分查找

二分查找有不同的应用:

  1. 找到 436. 寻找右区间 - 图14的位置(常见)
  2. 找到大于等于 436. 寻找右区间 - 图15的第一个位置
  3. 找到大于 436. 寻找右区间 - 图16的第一个位置
  4. 找到小于等于 436. 寻找右区间 - 图17的第一个位置
  5. 找到小于 436. 寻找右区间 - 图18的第一个位置

今天使用的就是第 2 种应用:「找到大于等于 436. 寻找右区间 - 图19的第一个位置」。

二分查找的本质是每次排除掉不可能存在结果的区间。

下面详细说明,如何在有序数组中,找到大于等于 436. 寻找右区间 - 图20的第一个位置。

首先,我们定义 436. 寻找右区间 - 图21指向数组的开始,定义 436. 寻找右区间 - 图22指向数组的结束,即当前搜索的空间是 436. 寻找右区间 - 图23双闭区间。

436. 寻找右区间 - 图24,即指向区间的中间位置。

每次判断 436. 寻找右区间 - 图25436. 寻找右区间 - 图26的大小:

  1. 如果 436. 寻找右区间 - 图27

说明 436. 寻找右区间 - 图28以及其左边的所有元素都不是「大于等于 436. 寻找右区间 - 图29的数字」。

因此令 436. 寻找右区间 - 图30

为什么需要 + 1?因为 436. 寻找右区间 - 图31 不符合要求,因此不在下次的搜索空间中

  1. 如果 436. 寻找右区间 - 图32,即 436. 寻找右区间 - 图33是大于等于 436. 寻找右区间 - 图34的位置。

说明 436. 寻找右区间 - 图35右边(不含 436. 寻找右区间 - 图36的所有元素都不是「第一个大于等于 436. 寻找右区间 - 图37的数字」。

因此令 436. 寻找右区间 - 图38

为什么不需要 + 1?因为 436. 寻找右区间 - 图39 有可能是结果,因此需要在下次的搜索空间中

举例。

代码

使用二分查找,找到区间右侧的第一个区间的起点。

然后我们通过字典(哈希表)再找到这个起点对应的区间的下标。

代码如下:

  1. class Solution:
  2. def findRightInterval(self, intervals: List[List[int]]) -> List[int]:
  3. n = len(intervals)
  4. start_map = {interval[0] : i for i, interval in enumerate(intervals)}
  5. start_list = [interval[0] for interval in intervals]
  6. res = []
  7. start_list.sort()
  8. for interval in intervals:
  9. pos = self.higher_find(start_list, interval[1])
  10. res.append(start_map[start_list[pos]] if pos != -1 else -1)
  11. return res
  12. def higher_find(self, nums, target):
  13. left, right = 0, len(nums) - 1
  14. # [left, right]
  15. while left < right:
  16. mid = left + (right - left) // 2
  17. if nums[mid] >= target:
  18. right = mid
  19. else:
  20. left = mid + 1
  21. if left >= len(nums) or nums[left] < target:
  22. return -1
  23. return left

总结

  1. 今天主要是题目很难理解;
  2. 二分查找的变形,也需要掌握,重点是理解。

我是 @负雪明烛 ,刷算法题 1000 多道,写了 1000 多篇算法题解,收获阅读量 300 万。
关注我,你将不会错过我的精彩动画题解、面试题分享、组队刷题活动,进入主页 @负雪明烛 右侧有刷题组织,从此刷题不再孤单。