1. 合并区间问题概述
LeetCode第56题"合并区间"是算法面试中的经典问题,也是Hot100高频题目之一。题目要求给定一个区间的集合,合并所有重叠的区间。这个问题看似简单,但考察了程序员对排序算法、数组操作和边界条件处理等基础能力的掌握程度。
在实际工程中,合并区间的场景非常常见。比如处理日程安排时合并重叠时间段、优化数据库查询的时间范围、合并网络设备的IP地址段等。掌握这个算法不仅能帮助通过技术面试,更能提升解决实际问题的能力。
2. 问题分析与解题思路
2.1 问题描述
给定一个区间的集合,其中每个区间表示为[start, end]。需要合并所有重叠的区间,并返回一个不重叠的区间数组。
示例: 输入:intervals = [[1,3],[2,6],[8,10],[15,18]] 输出:[[1,6],[8,10],[15,18]] 解释:区间[1,3]和[2,6]重叠,合并为[1,6]
2.2 关键观察点
- 区间重叠的判断标准:两个区间[a,b]和[c,d],如果a≤d且c≤b,则它们重叠
- 合并后的新区间取两个区间的最小开始值和最大结束值
- 输入区间可能无序,直接处理会导致复杂度高且难以正确合并
2.3 解题思路
最直观的解法是:
- 首先将所有区间按照起始点排序
- 初始化结果列表,放入第一个区间
- 遍历后续区间,与结果列表最后一个区间比较:
- 如果重叠,则合并
- 否则直接加入结果列表
这种解法的时间复杂度主要取决于排序步骤,为O(nlogn),空间复杂度为O(n)(存储结果)。
3. 代码实现与详细解析
3.1 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 merged3.2 代码解析
- 首先处理空输入的特殊情况
- 使用Python内置的sort方法,按区间起始点排序
- 初始化merged列表,放入第一个区间
- 遍历后续区间:
- 获取当前区间和merged中最后一个区间
- 检查是否重叠(当前区间的起始点≤最后一个区间的结束点)
- 如果重叠,则合并(取两个区间结束点的最大值)
- 否则将当前区间加入merged列表
3.3 边界条件处理
- 空输入:直接返回空列表
- 单个区间:无需合并,直接返回
- 完全包含的区间:如[1,4]和[2,3],合并为[1,4]
- 刚好相接的区间:如[1,2]和[2,3],可以合并为[1,3]
4. 复杂度分析与优化
4.1 时间复杂度
- 排序步骤:O(nlogn)
- 合并步骤:O(n)
- 总体时间复杂度:O(nlogn)
4.2 空间复杂度
- 排序:Python的sort方法空间复杂度为O(n)
- 存储结果:O(n)
- 总体空间复杂度:O(n)
4.3 优化思路
- 如果输入已经有序,可以跳过排序步骤,时间复杂度降为O(n)
- 可以使用原地算法减少空间使用,但会牺牲代码可读性
- 对于特定场景(如区间范围有限),可以使用计数排序将时间复杂度降为O(n)
5. 常见错误与调试技巧
5.1 常见错误
- 忘记排序:导致无法正确识别所有重叠区间
- 合并逻辑错误:如只更新结束点而不比较最大值
- 边界条件处理不当:如空输入或单个区间的情况
- 修改遍历中的列表:在遍历时修改原列表会导致意外行为
5.2 调试技巧
- 打印中间结果:在排序后和每次合并后打印当前状态
- 使用可视化工具:绘制区间图帮助理解合并过程
- 单元测试:针对各种边界情况编写测试用例
- 逐步执行:使用调试器一步步跟踪程序执行
6. 实际应用场景
6.1 日程安排系统
合并用户的多段可用时间,找出连续的可用时间段。例如:
- 输入:[[9,10],[10,12],[14,15],[13,14]]
- 输出:[[9,12],[13,15]]
6.2 网络IP地址管理
合并连续的IP地址段,优化路由表。例如:
- 输入:[[192.168.1.1,192.168.1.10],[192.168.1.5,192.168.1.15]]
- 输出:[[192.168.1.1,192.168.1.15]]
6.3 数据库查询优化
合并多个查询条件的时间范围,减少查询次数。例如:
- 输入:[[20230101,20230105],[20230103,20230110]]
- 输出:[[20230101,20230110]]
7. 变种问题与扩展
7.1 插入新区间
给定一组不重叠的区间(已排序)和一个新区间,插入并合并必要的区间。这是LeetCode第57题,可以看作是合并区间问题的扩展。
7.2 区间交集
给定两组已排序的区间列表,返回它们的交集。这是LeetCode第986题,需要同时遍历两个列表并比较区间。
7.3 会议室安排
给定一组会议时间区间,判断一个人是否能参加所有会议。这是LeetCode第252题,解法类似于检查是否有重叠区间。
8. 个人解题心得
在实际解决这个问题时,我最初尝试了不排序直接合并的方法,结果发现无法处理所有情况。经过几次失败后,我意识到排序是解决问题的关键步骤。这让我深刻理解到:对于区间问题,排序往往能大大简化问题复杂度。
另一个收获是关于边界条件的处理。最初我的代码在空输入时会出错,后来添加了相应的检查。这提醒我在解决算法问题时,一定要考虑各种边界情况,包括空输入、单个元素、完全包含等情况。
最后,我发现将这个问题可视化非常有帮助。画出区间在数轴上的表示,可以直观地理解合并的过程和条件。这种可视化思维在解决其他区间问题时也同样适用。