LeetCode热题100——56.合并区间

39 阅读2分钟

题目描述

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

 

示例:

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

  提示:

  • 1 <= intervals.length <= 104
  • intervals[i].length == 2
  • 0 <= starti <= endi <= 104

题解

贪心算法

/**
 * @param {number[][]} intervals
 * @return {number[][]}
 */
var merge = function(intervals) {
    intervals.sort((a,b)=>a[0]-b[0]);
    let pre = intervals[0];
    let result = [];
    for(let i = 0;i<intervals.length;i++){
        let cur = intervals[i];
        if(cur[0]>pre[1]){
            result.push(pre);
            pre = cur;
        }else{
            pre[1] = Math.max(cur[1],pre[1])
        }
    }
    result.push(pre);
    return result;
};

分析题目,解决思路是:找出重叠区间-合并重叠区间-返回结果

代码首先通过sort()方法先对数组进行排序,依据是按照内部的左边界从小到大排序。以便后续进行重叠的判断

排序完成后,采用贪心策略进行单次遍历合并:

  • pre: 存储当前正在构建、合并的区间(即上一个被合并后的结果)。初始化为排序后的第一个区间 intervals[0]
  • result: 存储最终不重叠的区间集合。

遍历逻辑: 从第二个区间开始遍历,将当前区间 cur 与正在构建的 pre 区间进行比较。

  • if(cur[0] > pre[1]):当前区间的起点 cur[0]\text{cur}[0] 大于上一个合并区间的终点 pre[1]\text{pre}[1]。说明curpre没有重叠
  1. 将已经完成合并的 pre 区间加入结果列表 result.push(pre)
  2. 将当前区间 cur 作为新的、待合并的区间起点:pre = cur
  • else(即 cur[0]pre[1]\text{cur}[0] \le \text{pre}[1]):当前区间的起点 cur[0]\text{cur}[0] 小于或等于上一个合并区间的终点 pre[1]\text{pre}[1]。即两个区间有重叠
  1. 这两个区间可以合并。
  2. 合并后的新终点应该是两者终点中较大的那个:pre[1] = Math.max(cur[1], pre[1])
  3. 保持 pre 不变,继续等待下一个区间。

结果处理

  • 循环结束后: 循环结束后,最后一个正在构建的 pre 区间还未被加入 result 列表。执行result.push(pre),以确保将最后一个合并完成的区间添加到结果中。

时间,空间复杂度

时间复杂度 O(N \log N)

排序操作是主要的时间开销,复杂度为 O(NlogN)O(N \log N)

空间复杂度:O(\log N) 或 O(N)

排序所需空间: O(logN)O(\log N)O(N)O(N)(取决于 JavaScript 引擎使用的排序算法)。

结果所需空间: O(N)O(N),最坏情况下(所有区间都不重叠)result 数组会存储 NN 个区间。

综合空间复杂度为 O(N)O(N)