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% 的区间题。
相关推荐
mjhcsp1 小时前
P3145 [USACO16OPEN] Splitting the Field G(题解)
开发语言·c++·算法
橘颂TA1 小时前
【剑斩OFFER】算法的暴力美学——力扣 675 题:为高尔夫比赛砍树
数据结构·算法·c·结构与算法
rit84324991 小时前
UVE算法提取光谱特征波长的MATLAB实现与应用
开发语言·算法·matlab
是娇娇公主~1 小时前
算法——【最大子数组和】
数据结构·c++·算法
tkevinjd1 小时前
力扣hot100-283移动零(盲人拉屎)
算法·leetcode
POLITE32 小时前
Leetcode 94. 二叉树的中序遍历 104. 二叉树的最大深度 226. 翻转二叉树 101. 对称二叉树 (Day 13)
算法·leetcode·职场和发展
老鼠只爱大米2 小时前
LeetCode经典算法面试题 #2:两数相加(迭代法、字符串修改法等多种实现方案详解)
算法·leetcode·链表·两数相加·字符串修改法·两数相减·大数运算
季明洵2 小时前
二分搜索、移除元素、有序数组的平方、长度最小的子数组
java·数据结构·算法·leetcode
XH华2 小时前
备战蓝桥杯,第一章:C++入门
c++·蓝桥杯