编码母题 / P0 / 经典算法 / 02

合并重叠区间

重要程度必练难度中等预计完成20–30 分钟

题目是什么

每个闭区间 [start,end] 均满足 start <= end,且端点为有限数字。输入若干区间,合并重叠项并按起点升序返回;端点相接也算重叠。不得修改原数组或内部区间,空数组返回 []。

输入输出示例

输入 [[1,3],[2,6],[8,10],[10,18]],输出 [[1,6],[8,18]];输入 [],输出 []。

练习起手式与验证

/*
 * 题目:合并重叠区间
 * 要求:每个闭区间 [start,end] 均满足 start <= end,且端点为有限数字。输入若干区间,合并重叠项并按起点升序返回;端点相接也算重叠。不得修改原数组或内部区间,空数组返回 []。
 * 示例:输入 [[1,3],[2,6],[8,10],[10,18]],输出 [[1,6],[8,18]];输入 [],输出 []。
 */
function mergeIntervals(intervals) {}
console.log(mergeIntervals([[1, 3], [2, 6], [8, 10], [10, 18]])); // 预期:[[1, 6], [8, 18]]
console.log(mergeIntervals([])); // 预期:[]
console.log(mergeIntervals([[1, 4], [2, 3]])); // 预期:[[1, 4]]
console.log(mergeIntervals([[1, 2], [2, 3]])); // 预期:[[1, 3]]

解题思路与实现

展开解题思路

先复制每个区间并按起点排序。扫描时若当前区间与下一项重叠,就把合并结果写到下一项,让它继续向后参与合并;否则提交当前区间。

function mergeIntervals(intervals) {
  // 输入保证每个区间满足 start <= end;复制两层以免排序和合并修改入参。
  const sorted = intervals
    .map(([start, end]) => [start, end])
    .sort((a, b) => a[0] - b[0]);
  const result = [];

  for (let i = 0; i < sorted.length; i++) {
    const current = sorted[i];
    const next = sorted[i + 1];

    if (next && current[1] >= next[0]) {
      // 把合并段交给下一轮,包含区间和链式重叠都不会漏掉。
      sorted[i + 1] = [current[0], Math.max(current[1], next[1])];
    } else {
      result.push(current);
    }
  }

  return result;
}

// 三组以上可直接运行的验证。
console.log(mergeIntervals([[1, 3], [2, 6], [8, 10], [10, 18]])); // 预期:[[1, 6], [8, 18]]
console.log(mergeIntervals([])); // 预期:[]
console.log(mergeIntervals([[1, 4], [2, 3]])); // 预期:[[1, 4]]
console.log(mergeIntervals([[1, 2], [2, 3]])); // 预期:[[1, 3]]
const original = [[8, 10], [1, 3], [2, 6]];
console.log(mergeIntervals(original)); // 预期:[[1, 6], [8, 10]]
console.log(original); // 预期:[[8, 10], [1, 3], [2, 6]]

时间复杂度:O(n log n)。复制与扫描各为 O(n),按起点排序占主导。

空间复杂度:O(n)。区间副本和返回结果各最多保存 n 个区间。

下载原始 JS 文件