hot100-合并区间(day14)

一、问题定义与核心需求

题目描述

传送门:合并区间

给定一个由若干区间组成的数组 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;
    }
};

关键代码解析

  1. 空输入处理if (intervals.empty()) return {};原代码未处理空输入,会导致 res.push_back(intervals[0]) 越界,这是面试高频坑点!
  2. 排序逻辑sort(intervals.begin(), intervals.end())C++ 的 sort 对二维 vector 默认按第一个元素升序排序,若第一个元素相等则按第二个元素升序,完全符合需求。
  3. 引用操作vector<int>& last = res.back();使用引用直接修改结果集最后一个区间,避免拷贝,提升效率。
  4. 合并规则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))

五、常见坑点与避坑指南

  1. 忽略空输入 :未处理 intervals.empty() 会导致数组越界;
  2. 排序遗漏:忘记排序直接遍历,会导致乱序区间无法正确合并(如示例 3);
  3. 合并时取最小值 :错误写成 last[1] = min(...),完全违背合并逻辑;
  4. 端点相等判定错误 :认为 [1,4][4,5] 不重叠,不符合题目要求。

六、拓展:区间问题的延伸应用

  1. 区间插入:给定一个无重叠区间数组,插入一个新区间并合并(核心逻辑:先插入再合并);
  2. 无重叠区间:找出需要移除的最少区间数,使剩余区间无重叠(贪心:按右端点排序,选最早结束的区间);
  3. 会议室预订:判断能否安排所有会议(本质是检查是否有重叠区间)。

七、总结

  1. 合并区间的核心是排序 + 贪心:排序保证遍历顺序,贪心仅需比较最后一个区间,时间复杂度最优;
  2. 边界条件(空输入、端点相等);
  3. 区间类问题的本质是排序 + 重叠判定,掌握这两个核心可解决 80% 的区间题。
相关推荐
To_OC6 小时前
LC 49 字母异位词分组:想到哈希表很简单,选对 key 才是精髓
javascript·算法·leetcode
用户9385156350711 小时前
从 O(n²) 到 O(nlogn):一文读懂快速排序的“快”与“妙”
javascript·算法
To_OC12 小时前
手写快排次次翻车?别死背快排模板了,这才是面试官想听的底层逻辑
javascript·算法·排序算法
饼干哥哥13 小时前
Reddit VOC调研太慢?搭一个AI专家团队半小时洞察任何品类|以猫用饮水机为例
人工智能·算法·ai编程
地平线开发者14 小时前
Transformer模型部署之性能优化指南
算法
地平线开发者15 小时前
人在途中:从“编译失败”到“模型可落地”——CUDA 自定义算子
算法·自动驾驶
半个落月18 小时前
从递归到快速排序:用 JavaScript 把分治思想讲明白
javascript·算法·面试
小月土星19 小时前
JavaScript 快速排序:从 pivot、双指针到分治思想
javascript·算法·面试
小月土星19 小时前
JavaScript 递归入门:从 1 到 n 求和,再到数组扁平化
javascript·算法·面试