算法 - 合并区间 (Merge Intervals)
1. 题目
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [start_i, end_i]。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。
示例:
1 | 输入: [[1,3],[2,6],[8,10],[15,18]] |
2. 解题思路
区间能否合并,取决于它们在数轴上的相对位置。若无序,两个区间可能隔着十万八千里却要判重,非常麻烦。核心思路:先按左端点排序,让可能重叠的区间彼此相邻,然后一次线性扫描。
排序后遍历,维护结果数组 res,对当前区间 cur:
- 若
res为空,或cur.start > res 最后一个.end(不重叠)→ 直接 push 新区间。 - 否则说明重叠 → 合并:更新最后一个区间的
end = max(旧end, cur.end)。
为什么是 max?考虑 [[1,10],[2,3]],第二个区间完全被包含,end 不能取 cur.end,要保留较大的那个。
- 时间复杂度:
O(n log n),排序主导。 - 空间复杂度:
O(n)(存结果;不计则为O(log n)排序栈)。
3. TypeScript 实现
1 | function merge(intervals: number[][]): number[][] { |
4. 面试延伸
- 插入区间(57 题):找到插入位置,把与新区间相交的全部吞并,取新端点。
- 区间相交 / 无重叠最少删除(435 题):按右端点排序 + 贪心,是另一条主线,别和本题的左端点排序搞混。
- 会议室 II(253 题):求同时进行的最多区间数,用最小堆或「起点/终点分别排序 + 双指针扫描线」。
- 通用套路:区间题先想排序策略(按左?按右?),再决定扫描时维护什么状态。
难度:中等 | LeetCode 56 题 | 排序 + 扫描线经典