返回
区间搜索难题?巧用「排序 + 二分」和「双指针」,轻松解决 LeetCode 436!
后端
2023-12-08 23:06:07
引言
在软件开发中,我们经常需要处理区间相关的问题。例如,我们需要查找重叠的区间、计算区间的覆盖长度,或者确定某个点是否落在某个区间内。LeetCode 的 436. 寻找右区间 就是这样一个经典的区间搜索问题。
问题
题目给定一个区间数组 intervals
,其中每个区间 interval
由其左端点 interval[0]
和右端点 interval[1]
定义。我们的目标是找到每个区间 interval
的「右区间」,即满足 interval[1] < rightInterval[0]
的最小 rightInterval
。如果这样的区间不存在,则返回 -1
。
「排序 + 二分」解法
「排序 + 二分」是一种高效的解法,它利用了区间的有序性。具体步骤如下:
- 排序区间: 按照区间的左端点对
intervals
进行升序排序。 - 二分查找右区间: 对于每个区间
interval
,使用二分查找在排序后的数组中找到满足interval[1] < rightInterval[0]
的最小rightInterval
。 - 返回结果: 如果找到
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
「双指针(莫队思想)」解法
「双指针(莫队思想)」是一种基于贪心的解法,它无需排序。具体步骤如下:
- 初始化两个指针:
left
和right
,分别指向intervals
的开头和结尾。 - 移动右指针: 不断向右移动
right
指针,直到找到满足intervals[right][0] >= intervals[left][1]
的条件。 - 更新结果: 如果找到这样的
rightInterval
,则更新intervals[left]
的「右区间」为right
。 - 移动左指针: 向右移动
left
指针。 - 重复步骤 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. 寻找右区间 问题的有效解法。前者利用了区间的有序性,而后者则基于贪心思想。根据不同的场景和数据规模,我们可以选择最合适的方法来解决问题。希望这篇文章能帮助您深入理解区间搜索算法,并将其应用到您的编程实践中。