LeetCode 56. 合并区间 | 排序+贪心解法详解
目录
TOC
题目描述
给定一组区间 intervals
,要求合并所有重叠的区间,返回一个不重叠的区间数组,且该数组需恰好覆盖输入中的所有区间。
cobol
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠,合并为 [1,6]。
解题思路
关键思路:排序 + 贪心
-
排序 :将所有区间按照起始点升序排列。这一步的目的是让可能重叠的区间相邻,便于后续合并。
-
合并 :遍历排序后的区间,逐个比较当前区间与下一个区间:
-
不重叠 :当前区间的右端点 < 下一区间的左端点 → 将当前区间加入结果。
-
重叠 :当前区间的右端点 ≥ 下一区间的左端点 → 合并两区间,右端点取两者的较大值。
- 处理末尾 :遍历结束后,最后一个合并的区间需加入结果。
为什么排序?
排序后,所有可能重叠的区间会连续出现。例如,排序后处理 [1,3]
和 [2,6]
,发现重叠后合并为 [1,6]
。此时只需继续与后续区间比较,无需回头处理前面的区间,保证线性时间复杂度。
代码实现
cobol
var merge = function (intervals) {
if (intervals.length === 0) return [];
intervals.sort((a, b) => a[0] - b[0]); // 按起始点排序
let result = [];
let current = intervals[0]; // 当前合并的区间
for (let i = 1; i < intervals.length; i++) {
if (intervals[i][0] > current[1]) { // 不重叠
result.push(current);
current = intervals[i];
} else { // 重叠,合并右端点
current[1] = Math.max(current[1], intervals[i][1]);
}
}
result.push(current); // 加入最后一个区间
return result;
};
复杂度分析
-
时间复杂度 :O(n log n),主要由排序决定。
-
空间复杂度 :O(n),存储结果数组。若排序使用额外空间,则为 O(log n)。
示例解析
以输入 [[1,3],[2,6],[8,10],[15,18]]
为例:
-
排序 :已按起始点排列。
-
合并过程 :
-
current = [1,3]
,与[2,6]
比较 → 合并为[1,6]
。 -
current = [1,6]
,与[8,10]
比较 → 不重叠,加入结果,current
更新为[8,10]
。 -
current = [8,10]
,与[15,18]
比较 → 不重叠,加入结果,current
更新为[15,18]
。
- 加入最后一个区间 → 最终结果
[[1,6],[8,10],[15,18]]
。
边界条件处理
-
空输入 :直接返回空数组。
-
单个区间 :直接返回该区间。
-
完全覆盖 :如
[[1,4],[2,3]]
→ 合并为[1,4]
。
总结
本题通过排序将问题转化为线性遍历合并,是典型的贪心策略。关键在于理解排序如何简化重叠判断,以及如何通过一次遍历合并所有可能的重叠区间。类似问题如插入区间(LeetCode 57)也可用类似思路解决。