Q2-LeetCode56-合并区间

69 阅读2分钟

实现思路

1 思考流程:

1.1 最简数据的 暴力解法: 每一项都 需要和 其他的每一项比较,复杂度是 O(n^2)

1.2 如何减少 需要比较的个数==> 让重叠区间相邻==> 只需要比较相邻区间==> 顺序处理

1.3 如何让重叠区间相邻==> 按开始位置排序

类比理解: 想象你在整理一堆纸条,每个纸条上写着时间段 自然而然会先按开始时间排序,再看哪些时间段重叠

1.4 什么排序后只看相邻的就可以了==>

想象三个区间,按开始位置排好序:

  • A: [1,5]
  • B: [2,4]
  • C: [3,7]

如果 A 能和 C 合并,那 B 一定也要参与合并,因为:

  • A 的结束位置是 5
  • C 的开始位置是 3
  • 既然 A 和 C 能合并,说明 5 ≥ 3
  • 而 B 的开始位置是 2,比 3 还小

所以 B 一定也会和 A 重叠

2 总结思维技巧:

  • 当遇到区间类问题/数据杂乱 时,排序常常是简化问题的第一步,因为它能把杂乱的关系变得有序,使问题变得可处理

3 合并区间 普遍性:

  • 按开始位置排序,以保证重叠区间是相邻的==> 从而实现可以 顺序处理,减少 需要比较的元素个数
  • 判断 区间是否重叠,重叠则合并,否则 直接加入结果数组

参考文档

01- 官方题解

代码实现

1 方法1: 排序 + 重叠区间合并,时间复杂度 O(nlogn) 空间复杂度O(n)

function merge(intervals) {
  if(intervals.length <= 1) return intervals;

  // 按开始位置排序区间,从而保证重叠区间是相邻的
  intervals.sort((a, b) => a[0] - b[0]);
  let res = [intervals[0]];
  // 多执行一次intervals[0]也不要紧
  for (const [start, end] of intervals) {
    const [preStart, preEnd] = res[res.length - 1];
    // 无重叠,直接加入到结果内
    if (start > preEnd) {
      res.push([start, end]);
    } else {
      // 有重叠(比较 cur区间的起始位置 和 pre区间的结束位置)==> 获取左右边界值
      res.pop();
      res.push([Math.min(start, preStart), Math.max(end, preEnd)]);
    }
  }
  return res;
}