全栈开发知识库

50.插入区间

题目

给你一个 无重叠的 ,按照区间起始端点排序的区间列表 intervals,其中 intervals[i] = [starti, endi] 表示第 i 个区间的开始和结束,并且 intervals 按照 starti 升序排列。同样给定一个区间 newInterval = [start, end] 表示另一个区间的开始和结束。

在 intervals 中插入区间 newInterval,使得 intervals 依然按照 starti 升序排列,且区间之间不重叠(如果有必要的话,可以合并区间)。

返回插入之后的 intervals。

注意 你不需要原地修改 intervals。你可以创建一个新数组然后返回它。

示例 1:

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

示例 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] 重叠。

提示:

  • 0 <= intervals.length <= 104
  • intervals[i].length == 2
  • 0 <= starti <= endi <= 105
  • intervals 根据 starti 按 升序 排列
  • newInterval.length == 2
  • 0 <= start <= end <= 105

思路

  • 题目说了是无重叠的按照区间起始端点排序的,所以不用排序了。
  • 用指针去扫 intervals,最多可能有三个阶段:

    • 不重叠的绿区间,在蓝区间的左边
    • 有重叠的绿区间
    • 不重叠的绿区间,在蓝区间的右边

image

  • 逐个分析

    • 不重叠,需满足:绿区间的右端,位于蓝区间的左端的左边,如 [1,2]。

      • 则当前绿区间,推入 res 数组,指针 +1,考察下一个绿区间。
      • 循环结束时,当前绿区间的屁股,就没落在蓝区间之间,有重叠了,如 [3,5]。

        • 现在看重叠的。我们反过来想,没重叠,就要满足:绿区间的左端,落在蓝区间的屁股的后面,反之就有重叠:绿区间的左端 <= 蓝区间的右端,极端的例子就是 [8,10]。
      • 和蓝有重叠的区间,会合并成一个区间:左端取蓝绿左端的较小者,右端取蓝绿右端的较大者,不断更新给蓝区间。

      • 循环结束时,将蓝区间(它是合并后的新区间)推入 res 数组。
        • 剩下的,都在蓝区间右边,不重叠。不用额外判断,依次推入 res 数组。

class Solution {
    fun insert(intervals: Array<IntArray>, newInterval: IntArray): Array<IntArray> {
        val res = mutableListOf<IntArray>()
        val len = intervals.size
        var i = 0

        while (i < len && intervals[i][1] < newInterval[0]) {
            res.add(intervals[i])
            i++
        }

        while (i < len && intervals[i][0] <= newInterval[1]) {
            if (intervals[i][0] < newInterval[0]) {
                newInterval[0] = intervals[i][0]
            }
            if (intervals[i][1] > newInterval[1]) {
                newInterval[1] = intervals[i][1]
            }
            i++
        }
        res.add(newInterval)

        while (i < len) {
            res.add(intervals[i])
            i++
        }

        return res.toTypedArray()
    }
}

class Solution {
    public int[][] insert(int[][] intervals, int[] newInterval) {
        ArrayList<int[]> res = new ArrayList<>();
        int len = intervals.length;
        int i = 0;
        // 判断左边不重合
        while (i < len && intervals[i][1] < newInterval[0]) {
            res.add(intervals[i]);
            i++;
        }
        // 判断重合
        while (i < len && intervals[i][0] <= newInterval[1]) {
            newInterval[0] = Math.min(intervals[i][0], newInterval[0]);
            newInterval[1] = Math.max(intervals[i][1], newInterval[1]);
            i++;
        }
        res.add(newInterval);
        // 判断右边不重合
        while (i < len && intervals[i][0] > newInterval[1]) {
            res.add(intervals[i]);
            i++;
        }
        return res.toArray(new int[0][]);
    }
}

复杂度分析:

  • 时间复杂度:O(n),其中 n 是数组 intervals 的长度,即给定的区间个数。

  • 空间复杂度:O(n)。



  • 邮箱 :charon.chui@gmail.com
  • Good Luck!