一、问题定义与核心需求
题目描述
传送门:合并区间
给定一个由若干区间组成的数组 intervals(单个区间为 [start_i, end_i]),合并所有重叠的区间,返回一个不重叠的区间数组,要求恰好覆盖输入的所有区间。
核心示例
| 输入 | 输出 | 核心逻辑 |
|---|---|---|
[[1,3],[2,6],[8,10],[15,18]] |
[[1,6],[8,10],[15,18]] |
[1,3] 与 [2,6] 重叠,合并为 [1,6] |
[[1,4],[4,5]] |
[[1,5]] |
端点相等视为重叠 |
[[4,7],[1,4]] |
[[1,7]] |
区间乱序时需先排序再合并 |
关键认知
重叠的判定规则:若区间 A 的右端点 ≥ 区间 B 的左端点,则 A 和 B 重叠(包括端点相等的情况)。
二、思路拆解:从暴力到最优
1. 暴力思路(O (n²),不推荐)
核心逻辑
- 遍历每个区间,与结果集中的所有区间逐一比较,若重叠则合并,否则加入结果集;
- 合并后需重新检查结果集(因为新合并的区间可能和其他区间重叠)。
问题
- 时间复杂度高(O (n²)),n 为区间数量;
- 逻辑冗余,重复检查导致效率低下;
- 乱序区间需多次回溯,极易出错。
结论
暴力思路仅适合理解 "重叠判定"。
2. 最优思路:排序 + 贪心(O (n log n),推荐)
核心原理
- 排序 :先按区间的左端点升序排序,保证后续遍历的区间左端点不会小于前面的区间;
- 贪心 :遍历排序后的区间,仅需与结果集中最后一个区间比较(因为排序后,若当前区间与最后一个不重叠,则与前面所有区间都不重叠)。
三、最优解代码实现与逐行解析
cpp
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
// 边界条件:空输入直接返回空结果
if (intervals.empty()) return {};
// 步骤1:按区间左端点升序排序(核心!)
// sort默认按vector第一个元素升序,第二个元素升序
sort(intervals.begin(), intervals.end());
// 步骤2:初始化结果集,加入第一个区间
vector<vector<int>> res;
res.push_back(intervals[0]);
// 步骤3:遍历剩余区间,贪心合并
for (int i = 1; i < intervals.size(); ++i) {
// 取结果集最后一个区间(引用,直接修改)
vector<int>& last = res.back();
// 当前区间的左端点
int curr_start = intervals[i][0];
// 当前区间的右端点
int curr_end = intervals[i][1];
// 判定:最后一个区间的右端点 ≥ 当前区间左端点 → 重叠
if (last[1] >= curr_start) {
// 合并:更新最后一个区间的右端点为两者最大值
last[1] = max(last[1], curr_end);
} else {
// 不重叠:直接加入结果集
res.push_back(intervals[i]);
}
}
return res;
}
};
关键代码解析
- 空输入处理 :
if (intervals.empty()) return {};原代码未处理空输入,会导致res.push_back(intervals[0])越界,这是面试高频坑点! - 排序逻辑 :
sort(intervals.begin(), intervals.end())C++ 的sort对二维 vector 默认按第一个元素升序排序,若第一个元素相等则按第二个元素升序,完全符合需求。 - 引用操作 :
vector<int>& last = res.back();使用引用直接修改结果集最后一个区间,避免拷贝,提升效率。 - 合并规则 :
last[1] = max(last[1], curr_end)必须取最大值(比如[1,5]和[2,3]重叠,合并后仍为[1,5])。
四、复杂度分析
| 操作 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 排序 | O(n log n) | O (log n)(排序的栈空间) |
| 遍历 | O(n) | O (1)(仅临时变量) |
| 总复杂度 | O(n log n) | O (n)(结果集空间,若不计则为 O (log n)) |
五、常见坑点与避坑指南
- 忽略空输入 :未处理
intervals.empty()会导致数组越界; - 排序遗漏:忘记排序直接遍历,会导致乱序区间无法正确合并(如示例 3);
- 合并时取最小值 :错误写成
last[1] = min(...),完全违背合并逻辑; - 端点相等判定错误 :认为
[1,4]和[4,5]不重叠,不符合题目要求。
六、拓展:区间问题的延伸应用
- 区间插入:给定一个无重叠区间数组,插入一个新区间并合并(核心逻辑:先插入再合并);
- 无重叠区间:找出需要移除的最少区间数,使剩余区间无重叠(贪心:按右端点排序,选最早结束的区间);
- 会议室预订:判断能否安排所有会议(本质是检查是否有重叠区间)。
七、总结
- 合并区间的核心是排序 + 贪心:排序保证遍历顺序,贪心仅需比较最后一个区间,时间复杂度最优;
- 边界条件(空输入、端点相等);
- 区间类问题的本质是排序 + 重叠判定,掌握这两个核心可解决 80% 的区间题。