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% 的区间题。
相关推荐
rannn_1114 小时前
【力扣hot100】链表专题|160、206、234、141、142
java·算法·leetcode·链表·面试·开发
数模竞赛Paid answer5 小时前
2026年华东杯数学建模B题医药物流安排问题解题全过程文档及程序
算法·数学建模·数据分析·华东杯
不会代码的小猴5 小时前
21. 泛型编程上
开发语言·c++·笔记·算法
营养充电站5 小时前
VS Code Git 工作树:解锁多分支并行开发的高效体验
leetcode·决策树·逻辑回归·散列表·模拟退火算法
青瓦梦滋6 小时前
传输层UDP/TCP协议
linux·网络·c++·网络协议·tcp/ip·udp
AI备案指南-满满6 小时前
大模型与算法备案全流程详解:从零到通过的完整指南
人工智能·算法·备案·大模型备案·算法备案
江畔柳前堤6 小时前
LLM 训练核心机制深度解析:Warmup、Cosine Decay 与 Perplexity 的完整知识体系
网络·人工智能·深度学习·算法·机器学习·语音识别
一只旭宝6 小时前
细讲C加加【9】C++ std::function与std::bind详解|仿函数、绑定器、类成员绑定、占位符、成员偏移指针
开发语言·c++·算法
良木林6 小时前
子串 - LeetCode hot 100
算法·leetcode·职场和发展