一、前置核心知识点
1. 区间问题通用思路
区间类问题的核心是排序 + 遍历合并:
- 先按区间左端点(或右端点)排序,消除无序性
- 遍历过程中维护一个 “当前合并区间”,与后续区间比较重叠 / 相邻关系
- 重叠 / 相邻则合并,否则将当前区间加入结果,开始维护新的区间
2. Python 列表排序与 key 参数
list.sort(key=..., reverse=False):原地排序key=lambda x: x[0]:按列表元素的 ** 第 0 位(左端点)** 升序排列reverse=True:可改为降序,本题无需降序- 作用:让所有区间按左端点从小到大排列,保证遍历时只需和前一个合并区间比较即可
二、经典算法题:合并区间(LeetCode 56)
题目描述
以数组 intervals 表示若干个区间的集合,其中单个区间为 [start_i, end_i]。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。
示例:
- 输入:
intervals = [[1,3],[2,6],[8,10],[15,18]] - 输出:
[[1,6],[8,10],[15,18]] - 解释:区间
[1,3]和[2,6]重叠,合并为[1,6]
最优解法:排序 + 遍历合并
核心思路
-
排序:按区间左端点从小到大排序,保证所有可能重叠的区间都挨在一起
-
初始化:将第一个区间加入结果列表,作为 “当前合并区间”
-
遍历合并:
- 若当前区间的左端点 ≤ 当前合并区间的右端点 → 重叠 / 相邻,更新合并区间的右端点为两者最大值
- 若当前区间的左端点 > 当前合并区间的右端点 → 不重叠,将当前合并区间加入结果,开始维护新的区间
-
返回结果:遍历结束后,将最后一个合并区间加入结果
代码实现
from typing import List
class Solution:
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
if not intervals:
return []
# 按区间左端点升序排序
intervals.sort(key=lambda x: x[0])
merged = [intervals[0]] # 初始化结果列表,放入第一个区间
for current in intervals[1:]:
last = merged[-1] # 取结果中最后一个已合并的区间
# 当前区间左端点 <= 最后一个区间右端点 → 重叠/相邻,合并
if current[0] <= last[1]:
# 更新右端点为两者最大值
merged[-1] = [last[0], max(last[1], current[1])]
else:
# 不重叠,直接加入结果
merged.append(current)
return merged
三、关键逻辑详解
1. 排序的必要性
只有按左端点排序后,才能保证:
- 所有可能与当前区间重叠的区间,一定出现在它之后
- 只需和结果中最后一个合并区间比较,无需回溯之前的区间
2. 合并判断条件
-
current[0] <= last[1]:- 重叠:如
[1,3]和[2,6] - 相邻:如
[1,3]和[3,5](也需要合并为[1,5])
- 重叠:如
-
合并后右端点取最大值:
max(last[1], current[1]),保证覆盖完整区间
3. 边界处理
- 空输入:直接返回空列表
- 单区间输入:直接返回原区间
- 全重叠区间:最终合并为一个区间
四、算法复杂度与拓展
复杂度分析
- 时间复杂度:O (n log n),主要来自排序;遍历为 O (n)
- 空间复杂度:O (log n) ~ O (n),排序的栈空间 + 结果存储(最坏情况无重叠,需要 O (n))
拓展场景
该思路可直接迁移到:
- 插入区间:先插入再合并
- 区间列表的交集:双指针遍历两个排序后的区间列表
- 删除区间:遍历并拆分重叠区间