返回

区间搜索难题?巧用「排序 + 二分」和「双指针」,轻松解决 LeetCode 436!

后端

引言

在软件开发中,我们经常需要处理区间相关的问题。例如,我们需要查找重叠的区间、计算区间的覆盖长度,或者确定某个点是否落在某个区间内。LeetCode 的 436. 寻找右区间 就是这样一个经典的区间搜索问题。

问题

题目给定一个区间数组 intervals,其中每个区间 interval 由其左端点 interval[0] 和右端点 interval[1] 定义。我们的目标是找到每个区间 interval 的「右区间」,即满足 interval[1] < rightInterval[0] 的最小 rightInterval。如果这样的区间不存在,则返回 -1

「排序 + 二分」解法

「排序 + 二分」是一种高效的解法,它利用了区间的有序性。具体步骤如下:

  1. 排序区间: 按照区间的左端点对 intervals 进行升序排序。
  2. 二分查找右区间: 对于每个区间 interval,使用二分查找在排序后的数组中找到满足 interval[1] < rightInterval[0] 的最小 rightInterval
  3. 返回结果: 如果找到 rightInterval,则返回其索引;否则返回 -1

代码示例:

def findRightInterval(intervals):
    # 排序区间
    intervals.sort(key=lambda x: x[0])

    # 初始化结果数组
    result = [-1] * len(intervals)

    for i, interval in enumerate(intervals):
        # 二分查找右区间
        left, right = 0, len(intervals) - 1
        while left < right:
            mid = (left + right) // 2
            if intervals[mid][0] >= interval[1]:
                right = mid
            else:
                left = mid + 1

        # 检查是否找到
        if intervals[left][0] >= interval[1]:
            result[i] = left

    return result

「双指针(莫队思想)」解法

「双指针(莫队思想)」是一种基于贪心的解法,它无需排序。具体步骤如下:

  1. 初始化两个指针: leftright,分别指向 intervals 的开头和结尾。
  2. 移动右指针: 不断向右移动 right 指针,直到找到满足 intervals[right][0] >= intervals[left][1] 的条件。
  3. 更新结果: 如果找到这样的 rightInterval,则更新 intervals[left] 的「右区间」为 right
  4. 移动左指针: 向右移动 left 指针。
  5. 重复步骤 2-4: 直到 left 指针到达数组末尾。

代码示例:

def findRightInterval(intervals):
    # 初始化结果数组
    result = [-1] * len(intervals)

    # 初始化指针
    left, right = 0, 0

    while left < len(intervals):
        # 移动右指针
        while right < len(intervals) and intervals[right][0] < intervals[left][1]:
            right += 1

        # 更新结果
        if right < len(intervals):
            result[left] = right

        # 移动左指针
        left += 1

    return result

总结

「排序 + 二分」和「双指针(莫队思想)」都是解决 LeetCode 436. 寻找右区间 问题的有效解法。前者利用了区间的有序性,而后者则基于贪心思想。根据不同的场景和数据规模,我们可以选择最合适的方法来解决问题。希望这篇文章能帮助您深入理解区间搜索算法,并将其应用到您的编程实践中。