LeetCode 第56题:合并区间

110 阅读4分钟

LeetCode 第56题:合并区间

题目描述

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。

难度

中等

题目链接

点击在LeetCode中查看题目

示例

示例 1:

输入:intervals = [[1,3],[2,6],[8,10],[15,18]] 输出:[[1,6],[8,10],[15,18]] 解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

示例 2:

输入:intervals = [[1,4],[4,5]] 输出:[[1,5]] 解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。

提示

  • 1 <= intervals.length <= 10^4
  • intervals[i].length == 2
  • 0 <= starti <= endi <= 10^4

解题思路

排序 + 一次遍历

这道题的核心思想是先对区间按照起始位置排序,然后遍历一次数组进行合并。

关键点:

  1. 按区间起始位置排序,保证区间有序
  2. 维护当前合并区间,与下一个区间比较
  3. 判断是否需要合并的条件:当前区间的结束位置 >= 下一个区间的起始位置
  4. 合并时取两个区间结束位置的最大值

具体步骤:

  1. 对区间数组按照起始位置排序
  2. 创建结果列表,将第一个区间加入
  3. 遍历剩余区间,判断是否需要与结果列表中最后一个区间合并
  4. 如果需要合并,更新结果列表最后一个区间的结束位置
  5. 如果不需要合并,将当前区间加入结果列表

图解思路

算法步骤分析表

步骤当前区间结果列表操作说明
初始[1,3][[1,3]]添加第一个区间直接添加
第1步[2,6][[1,6]]合并2<=3,需要合并
第2步[8,10][[1,6],[8,10]]添加8>6,不需要合并
第3步[15,18][[1,6],[8,10],[15,18]]添加15>10,不需要合并

状态/情况分析表

情况输入输出说明
基本情况[[1,3],[2,6],[8,10],[15,18]][[1,6],[8,10],[15,18]]标准合并
完全重叠[[1,4],[2,3]][[1,4]]一个区间包含另一个
相邻重叠[[1,4],[4,5]][[1,5]]边界相等也算重叠

代码实现

C# 实现

public class Solution {
    public int[][] Merge(int[][] intervals) {
        if (intervals == null || intervals.Length <= 1) 
            return intervals;
        
        // 按照区间起点排序
        Array.Sort(intervals, (a, b) => a[0].CompareTo(b[0]));
        
        var result = new List<int[]>();
        var current = intervals[0];
        
        foreach (var interval in intervals) {
            if (current[1] >= interval[0]) {
                // 有重叠,更新当前区间的结束位置
                current[1] = Math.Max(current[1], interval[1]);
            } else {
                // 无重叠,添加当前区间并更新
                result.Add(current);
                current = interval;
            }
        }
        
        // 添加最后一个区间
        result.Add(current);
        return result.ToArray();
    }
}

C# 执行结果:

  • 执行用时:168 ms
  • 内存消耗:46.2 MB

Python 实现

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        if not intervals:
            return []
        
        # 按照区间起点排序
        intervals.sort(key=lambda x: x[0])
        
        merged = []
        current = intervals[0]
        
        for interval in intervals:
            if current[1] >= interval[0]:
                # 有重叠,更新当前区间的结束位置
                current[1] = max(current[1], interval[1])
            else:
                # 无重叠,添加当前区间并更新
                merged.append(current)
                current = interval
        
        # 添加最后一个区间
        merged.append(current)
        return merged

Python 执行结果:

  • 执行用时:52 ms
  • 内存消耗:18.9 MB

C++ 实现

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        if (intervals.empty()) 
            return {};
            
        // 按照区间起点排序
        sort(intervals.begin(), intervals.end());
        
        vector<vector<int>> merged;
        merged.push_back(intervals[0]);
        
        for (int i = 1; i < intervals.size(); i++) {
            if (merged.back()[1] >= intervals[i][0]) {
                // 有重叠,更新当前区间的结束位置
                merged.back()[1] = max(merged.back()[1], intervals[i][1]);
            } else {
                // 无重叠,添加新区间
                merged.push_back(intervals[i]);
            }
        }
        
        return merged;
    }
};

C++ 执行结果:

  • 执行用时:36 ms
  • 内存消耗:18.1 MB

性能对比

语言执行用时内存消耗特点
C++36 ms18.1 MB性能最优
Python52 ms18.9 MB代码简洁
C#168 ms46.2 MB可读性好

代码亮点

  1. 🎯 使用排序+一次遍历的高效算法
  2. 💡 通过List动态存储结果,避免额外空间
  3. 🔍 巧妙处理区间合并的边界情况
  4. 🎨 代码结构清晰,逻辑简洁

常见错误分析

  1. 🚫 忘记对区间进行排序
  2. 🚫 合并条件判断错误
  3. 🚫 更新合并区间时未取最大值
  4. 🚫 未处理边界情况

解法对比

解法时间复杂度空间复杂度优点缺点
暴力比较O(n²)O(n)思路简单效率低
排序+遍历O(nlogn)O(n)最优解需要排序
优先队列O(nlogn)O(n)适合流式数据实现复杂

相关题目