1. 题目背景与核心思路
力扣第56题和第57题是经典的数组区间操作问题,这两道题在面试中出现的频率相当高。56题要求合并所有重叠的区间,57题则是在已排序的非重叠区间列表中插入一个新的区间并合并。这类问题考察的是对数组操作和边界条件的处理能力。
我在第一次做这两道题时,花了将近两个小时才通过所有测试用例。后来经过反复练习和总结,现在能在15分钟内写出bug-free的代码。下面分享我的解题思路和优化过程。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 问题分析与解法选择
2.1 第56题:合并区间
给定一个区间的集合,要求合并所有重叠的区间。例如:
输入:[[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
关键点在于:
- 区间需要先按照起始位置排序
- 维护一个当前合并区间,依次处理每个区间
- 判断是否需要合并(当前区间的起始位置 <= 合并区间的结束位置)
2.2 第57题:插入区间
给定一个无重叠的区间列表,且列表按照区间起始位置排序。现在要插入一个新的区间,并合并所有重叠的区间。例如:
输入:intervals = [[1,3],[6,9]], newInterval = [2,5]
输出:[[1,5],[6,9]]
这道题可以看作是56题的变种,关键在于:
- 找到新区间应该插入的位置
- 处理与新区间有重叠的区间
- 合并这些区间
3. 详细解题步骤
3.1 第56题实现代码
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
关键点说明:
- 先处理空输入的情况
- 使用lambda表达式按区间起始位置排序
- 维护一个merged列表存储合并结果
- 比较当前区间与最后一个合并区间的结束位置
3.2 第57题实现代码
python复制def insert(intervals, newInterval):
merged = []
i = 0
n = len(intervals)
# 添加所有在新区间之前且不重叠的区间
while i < n and intervals[i][1] < newInterval[0]:
merged.append(intervals[i])
i += 1
# 合并所有与新区间重叠的区间
while i < n and intervals[i][0] <= newInterval[1]:
newInterval[0] = min(newInterval[0], intervals[i][0])
newInterval[1] = max(newInterval[1], intervals[i][1])
i += 1
merged.append(newInterval)
# 添加剩余的区间
while i < n:
merged.append(intervals[i])
i += 1
return merged
关键点说明:
- 分三个阶段处理:不重叠的前置区间、重叠区间、不重叠的后置区间
- 在合并阶段动态更新新区间的范围
- 时间复杂度O(n),只需要一次遍历
4. 边界条件与测试用例
4.1 常见边界情况
- 空输入:intervals = [], newInterval = [2,5]
- 新区间在最前面:intervals = [[3,5]], newInterval = [1,2]
- 新区间在最后面:intervals = [[1,2]], newInterval = [3,5]
- 完全包含:intervals = [[1,5]], newInterval = [2,3]
- 多个重叠:intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
4.2 测试代码示例
python复制def test_merge():
assert merge([[1,3],[2,6],[8,10],[15,18]]) == [[1,6],[8,10],[15,18]]
assert merge([[1,4],[4,5]]) == [[1,5]]
assert merge([]) == []
def test_insert():
assert insert([[1,3],[6,9]], [2,5]) == [[1,5],[6,9]]
assert insert([[1,2],[3,5],[6,7],[8,10],[12,16]], [4,8]) == [[1,2],[3,10],[12,16]]
assert insert([], [5,7]) == [[5,7]]
5. 算法复杂度分析
-
时间复杂度:
- 排序:O(nlogn)(56题)
- 合并/插入:O(n)
- 总体:O(nlogn)(由排序步骤决定)
-
空间复杂度:
- 需要额外O(n)空间存储结果
- 如果允许原地修改,可以优化到O(1)
6. 常见错误与调试技巧
6.1 常见错误类型
- 忘记排序:导致合并不彻底
- 边界条件处理不当:空输入、单区间等情况
- 合并逻辑错误:特别是结束位置的更新
- 索引越界:在57题中处理i时容易出错
6.2 调试技巧
- 打印中间结果:在关键步骤打印merged列表
- 可视化区间:画数轴帮助理解
- 单元测试:先写测试用例再写代码
- 边界测试:专门测试空输入、单元素等情况
7. 同类问题扩展
- 力扣252. 会议室:判断一个人是否能参加所有会议
- 力扣253. 会议室II:计算需要的最少会议室数量
- 力扣435. 无重叠区间:找到需要移除区间的最小数量
- 力扣452. 用最少数量的箭引爆气球
这些题目都是区间问题的变种,核心思路都是先排序再处理,只是判断条件和处理逻辑有所不同。掌握了56和57题的解法后,这些题目都能迎刃而解。
8. 个人刷题心得
- 区间问题先排序:这是解决这类问题的关键第一步
- 画图辅助理解:在纸上画出区间关系能帮助理清思路
- 分步处理:像57题那样分阶段处理往往更清晰
- 多写测试用例:特别是边界情况,能发现很多潜在问题
- 总结模式:区间问题有固定套路,掌握后能举一反三
经过多次练习,我现在看到区间问题就会条件反射地想到排序+合并的思路。这种模式识别能力是刷题的重要收获之一。建议初学者可以把这两道题作为区间问题的入门题目,反复练习直到完全掌握。
