在问 · 算法题解

57. 插入区间

题目描述

输入区间列表 intervals,其中 intervals[i] = [starti, endi]。这些区间互不重叠,并且按 starti 从小到大排好。另给一个新区间 newInterval = [start, end]。

两个区间只要有至少一个公共点,就视为重叠。

把 newInterval 放进列表。如果它和已有区间重叠,就把这些区间合并成一个。最终列表仍须按起点升序,且区间两两不重叠。

返回处理后的区间列表。可以新建数组返回,不必原地修改 intervals。

示例 1
输入:intervals = [[1,3],[6,9]], newInterval = [2,5]
输出:[[1,5],[6,9]]

解释:[2,5] 和 [1,3] 重叠,合成 [1,5]。

示例 2
输入:intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
输出:[[1,2],[3,10],[12,16]]

解释:[4,8] 同时和 [3,5]、[6,7]、[8,10] 重叠,四者合成 [3,10]。

数据范围

  • 0 <= intervals.length <= 10^4
  • intervals[i].length == 2
  • 0 <= starti <= endi <= 10^5
  • intervals 已按 starti 升序排列。
  • newInterval.length == 2
  • 0 <= start <= end <= 10^5

解题思路

原列表已经有序,所以所有区间可以按与新区间的关系分成三段:完全在左边的(右端 < s)、与新区间重叠的、完全在右边的。左段原样放入结果;重叠段逐个并入 [s, e],用 min/max 扩张边界;然后放入合并后的 [s, e];最后原样追加右段。一次扫描就能完成,不需要重新排序。

为什么正确

第二段循环中,[s, e] 始终等于新区间与已扫描重叠区间的并集;res 中的区间始终有序且互不重叠。

复杂度分析

时间 O(n),除结果外额外空间 O(1)。

易错点

判断重叠时端点相接也算重叠:[1,3] 与 [3,6] 要合并,所以条件是 intervals[i][0] <= e 和 intervals[i][1] < s(左段用严格小于)。另外别忘了 intervals 为空或新区间在最右边时,也要把 [s, e] 放进结果。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]:
        res = []
        s, e = newInterval
        i, n = 0, len(intervals)
        while i < n and intervals[i][1] < s:
            res.append(intervals[i])
            i += 1
        while i < n and intervals[i][0] <= e:
            s = min(s, intervals[i][0])
            e = max(e, intervals[i][1])
            i += 1
        res.append([s, e])
        while i < n:
            res.append(intervals[i])
            i += 1
        return res

载入编辑器,自己跑一遍 →

数组与矩阵 专题的其他题目

查看 数组与矩阵 全部题目 →