1. 问题背景与需求分析
合并区间是算法面试中的经典问题,在LeetCode上编号为56题(Merge Intervals)。这个问题在实际开发中有广泛的应用场景,比如处理日程安排、合并时间窗口、优化资源分配等。
问题的核心是:给定一组区间,合并所有重叠的区间。例如:
- 输入:[[1,3],[2,6],[8,10],[15,18]]
- 输出:[[1,6],[8,10],[15,18]]
这个问题看似简单,但有几个关键点需要考虑:
- 区间可能以任意顺序出现
- 可能存在完全包含的区间
- 结果需要保证有序
- 边界条件处理(空输入、单个区间等)
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 贪心算法原理与适用性分析
贪心算法(Greedy Algorithm)是解决合并区间问题的最佳选择,这是因为它具有以下特性:
2.1 贪心算法的核心思想
贪心算法在每一步选择中都采取当前状态下最优的选择,从而希望导致全局最优的结果。对于合并区间问题,这意味着:
- 首先对所有区间按照起始点排序
- 初始化结果列表,放入第一个区间
- 遍历后续区间,每次只考虑当前区间是否能与结果列表中的最后一个区间合并
2.2 为什么贪心算法适用
合并区间问题具有贪心选择性质,即局部最优解能导致全局最优解。这是因为:
- 排序后,区间是按起始点有序排列的
- 每次只需要考虑当前区间与最后一个合并结果的比较
- 不需要回溯或考虑之前的所有可能性
这种特性使得贪心算法的时间复杂度可以达到O(nlogn),主要是排序的开销,而合并过程本身是O(n)的线性扫描。
3. 详细实现步骤与代码解析
3.1 Python实现代码
python复制def merge(intervals):
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]:
# 合并区间
last[1] = max(last[1], current[1])
else:
merged.append(current)
return merged
3.2 关键步骤解析
-
排序预处理:
intervals.sort(key=lambda x: x[0])- 这是贪心算法的关键,确保我们可以线性处理区间
- 排序标准是区间的起始点
-
初始化合并列表:
merged = [intervals[0]]- 从第一个区间开始构建结果
- 这样可以在遍历时始终与最后一个合并区间比较
-
合并逻辑:
if current[0] <= last[1]:- 判断当前区间是否与最后一个合并区间重叠
- 重叠条件:当前区间的起始点 <= 最后一个合并区间的结束点
-
合并操作:
last[1] = max(last[1], current[1])- 合并时取两个区间结束点的最大值
- 这样可以处理完全包含的情况
4. 复杂度分析与优化空间
4.1 时间复杂度
- 排序:O(nlogn),Python的Timsort算法
- 合并:O(n),线性扫描
- 总体:O(nlogn)
4.2 空间复杂度
- 最坏情况下需要O(n)空间存储结果
- 如果允许修改输入,可以原地操作,但一般不推荐
4.3 可能的优化
- 对于特定场景(如区间范围有限),可以使用计数排序将排序时间降到O(n)
- 并行化排序过程(对于极大数据集)
- 使用更紧凑的数据结构存储区间
5. 边界条件与测试用例
5.1 必须考虑的边界情况
- 空输入:
[]→ 返回[] - 单个区间:
[[1,3]]→ 返回[[1,3]] - 完全不重叠:
[[1,2],[3,4]]→ 返回[[1,2],[3,4]] - 完全包含:
[[1,4],[2,3]]→ 返回[[1,4]] - 负数和零:
[[-2,-1],[0,1]]→ 返回[[-2,-1],[0,1]]
5.2 测试用例示例
python复制test_cases = [
([], []),
([[1,3]], [[1,3]]),
([[1,4],[4,5]], [[1,5]]),
([[1,3],[2,6],[8,10],[15,18]], [[1,6],[8,10],[15,18]]),
([[1,4],[0,4]], [[0,4]]),
([[1,4],[2,3]], [[1,4]])
]
for intervals, expected in test_cases:
assert merge(intervals) == expected
6. 实际应用场景扩展
合并区间算法在现实中有多种应用:
- 会议室安排:合并可用的时间段,找出最长连续可用时间
- 磁盘碎片整理:合并空闲的磁盘块
- 基因序列分析:合并重叠的基因片段
- 交通调度:合并车辆运行时间窗口
- 项目管理:合并任务的时间区间,识别关键路径
7. 常见错误与调试技巧
7.1 新手常见错误
- 忘记排序:直接遍历会导致合并不彻底
- 错误的重叠判断:使用
<而不是<=可能漏掉相接的区间 - 修改迭代中的列表:在遍历时修改原列表会导致意外行为
- 忽略空输入:没有检查空列表直接访问第一个元素
7.2 调试建议
- 打印中间状态:在合并前后打印
merged列表 - 可视化区间:绘制区间图帮助理解
- 从小例子开始:先手动计算预期结果
- 使用断言:验证不变式,如结果列表应始终有序
8. 算法变种与进阶思考
- 插入新区间:在已排序的区间列表中插入并合并新区间
- 求交集:找出两组区间的交集部分
- 最小覆盖:用最少数量的区间覆盖所有给定区间
- 区间删除:删除特定区间后合并剩余区间
- 多维度区间:扩展到二维或更高维度的区间合并
对于插入新区间的问题,可以这样解决:
python复制def insert(intervals, newInterval):
intervals.append(newInterval)
return merge(intervals)
虽然这样可行,但有更优的O(n)解法,留给读者思考。
