面试经典150题[049]:合并区间(LeetCode 56)
合并区间(LeetCode 56)
题目链接:合并区间(LeetCode 56)
难度:中等
1. 题目描述
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
要求:
- 1 <= intervals.length <= 10^4
- intervals[i].length == 2
- 0 <= starti <= endi <= 10^4
示例:
输入: intervals = [[1,3],[2,6],[8,10],[15,18]]
输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
输入: intervals = [[1,4],[4,5]]
输出: [[1,5]]
解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。
输入: intervals = [[4,7],[1,4]]
输出: [[1,7]]
解释: 区间 [1,4] 和 [4,7] 可被视为重叠区间。
2. 问题分析
2.1 规律
- 区间可能无序且可能重叠或相接(end_i == start_j 被视为重叠)。
- 不排序的话,重叠区间可能不连续,导致合并复杂。
- 核心问题:如何高效检测并合并所有重叠部分,确保覆盖所有输入区间且无重叠输出?
2.2 贪心思路
我们使用排序 + 贪心算法:
- 先按起始点(start)升序排序intervals。如果start相同,可按end排序,但不影响。
- 初始化结果列表result,添加第一个区间。
- 遍历剩余区间:
- 如果当前区间的start <= result最后一个区间的end,说明重叠或相接:
- 更新result最后一个区间的end = max(原end, 当前end),贪心选择最大end覆盖更多。
- 否则,无重叠,添加当前区间到result。
- 如果当前区间的start <= result最后一个区间的end,说明重叠或相接:
- 这样确保输出区间不重叠且覆盖所有输入。
3. 代码实现
Python
class Solution:def merge(self, intervals):if not intervals:return []intervals.sort(key=lambda x: x[0])result = [intervals[0]]for interval in intervals[1:]:if interval[0] <= result[-1][1]:result[-1][1] = max(result[-1][1], interval[1])else:result.append(interval)return result
C++
class Solution {
public:std::vector<std::vector<int>> merge(std::vector<std::vector<int>>& intervals) {if (intervals.empty()) return {};std::sort(intervals.begin(), intervals.end(), [](const std::vector<int>& a, const std::vector<int>& b) {return a[0] < b[0];});std::vector<std::vector<int>> result;result.push_back(intervals[0]);for (size_t i = 1; i < intervals.size(); ++i) {if (intervals[i][0] <= result.back()[1]) {result.back()[1] = std::max(result.back()[1], intervals[i][1]);} else {result.push_back(intervals[i]);}}return result;}
};
4. 复杂度分析
- 时间复杂度:O(n log n),排序主导,合并为O(n)
- 空间复杂度:O(n),用于结果列表;排序空间O(log n)
5. 总结
- 区间合并问题 → 排序是关键,确保重叠连续
- 贪心维护最大end,很高效
- 类似会议室问题或区间调度
- 可扩展到插入新区间或计算重叠数
复习
面试经典150题[019]:最后一个单词的长度(LeetCode 58)
面试经典150题[034]:有效的数独(LeetCode 36)