图解题库 / 区间 · 合并

56. 合并区间

中等 含交互动画

学完这道你应该能: 说清它为什么用「合并」,而不是死记步骤; 合上页面,自己默写出核心代码; 用 30 秒把思路讲清楚。

题目描述

给若干区间 [start, end],把所有有重叠的合并掉,返回合并后互不重叠的区间列表。

输入 = [[1,3],[2,6],[8,10],[15,18]]
输出 = [[1,6],[8,10],[15,18]]

思路解析

区间顺序乱的时候两两比,不光慢,还容易漏掉「合并后又跟别人重叠」的情况,逻辑很绕。

排序后,可能重叠的区间必然相邻。这样只需从左到右扫一遍,拿当前区间跟「结果里最后一个」比就够了。

判重叠只看一句:当前区间的起点,是不是没超过结果里最后那个区间的终点。是就合并(终点取更大的),不是就新开一段。

排序后,处理 [1,3]:已经按起点排好序。第一个 [1,3] 没东西可比,直接放进结果。

处理 [2,6]:[2,6] 的起点 2 没超过上一个的终点 3,重叠!合并成 [1,6],终点取两者里更大的 6。

处理 [8,10]:[8,10] 的起点 8 已经超过上一段终点 6,接不上了,新开一个区间。

处理 [15,18]:[15,18] 同样接不上,再新开一段。扫完,结果就是 [[1,6],[8,10],[15,18]]

区间题的万能第一步——按端点排序。排完之后,绝大多数区间问题都能一遍扫描搞定,只跟「结果里最后一个」打交道。

参考代码(Python)

Python
1def merge(intervals):
2    intervals.sort(key=lambda x: x[0])     # 关键:按起点排序
3    res = []
4    for s, e in intervals:
5        if res and s <= res[-1][1]:        # 和上一段重叠
6            res[-1][1] = max(res[-1][1], e)  # 合并:拉长终点
7        else:
8            res.append([s, e])             # 接不上,新开
9    return res

复杂度分析

  • 时间复杂度:O(n log n) —— 排序主导,扫描只 O(n)
  • 空间复杂度:O(n) —— 存结果

套路模板

骨架记牢:排序 → 扫描 → 比末段终点决定合并还是新开。合并时终点一定要取 max,别忘了。

Python
1intervals.sort(key=lambda x: x[0])
2res = []
3for s, e in intervals:
4    if res and s <= res[-1][1]:
5        res[-1][1] = max(res[-1][1], e)
6    else:
7        res.append([s, e])

易错点

  • 不排序直接扫 → ✅ 先按起点 sort(不排序的话重叠区间未必相邻,一遍扫描会漏合并)
  • 合并时直接用 e 当新终点 → ✅ res[-1][1] = max(res[-1][1], e)(当前区间可能被上一段完全包住(e 更小),不取 max 会把终点改短)
  • 判重叠用 s < res[-1][1](漏等号) → ✅ s <= res[-1][1]([1,3] 和 [3,5] 端点相接也算重叠,要带等号)

以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握

下一题 →560. 和为 K 的子数组 ← 返回题库