[LeetCode] 57. Insert Interval

Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary).

You may assume that the intervals were initially sorted according to their start times.

Example 1:

Input: intervals = [[1,3],[6,9]], newInterval = [2,5]
Output: [[1,5],[6,9]]

Example 2:

Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
Output: [[1,2],[3,10],[12,16]]
Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10].

NOTE: input types have been changed on April 15, 2019. Please reset to default code definition to get new method signature.

插入区间。这题也是用到扫描线思想,题意是给了一个二维数组intervals,存放了一堆区间[start, end],又给了一个新的区间newInterval,需要把newInterval塞入intervals。(以下用第二个example举例)思路是

  • 遍历intervals,把跟newInterval没有交集的interval先加入结果集,这里是用每个interval的end去跟newInterval的start作比较,所有满足条件subinterval[1] < newInterval[0]的subinterval会被直接加入结果集
    • 例子,比如[4, 8]一直都是和每个subinterval的end比较,比如和[1, 2]的2比较,和[3, 5]的5比较
  • newInterval开始跟某些intervals有交集了,此时此刻需要开始merge。判断newInterval和某个interval有交集的方法是判断是否有某个interval的start小于newInterval的end。
    • 但是为什么代码里直接给出的是intervals[i][0] <= newInterval[1]呢?这个判断条件不是很直观。这个判断条件实际包含了好几种情况
      • intervals[i]的左边界 <= newInterval的左边界一样的情况下,谁的左边界小就用谁的左边界,谁的右边界大就用谁的右边界。这里相当于是修改某一个interval的边界,应该很好理解。比如[3, 5]和[4, 8]的处理。
      • 但是处理完[3, 5]和[4, 8]得到[3, 8],你发现后面的[6, 7]实际上还要接着一块merge,所以这里只能用while循环,一直往后看,看是否还有更多的subinterval等待被merge。在while循环跳出后,才把这个新的interval加入结果集。
      • 这样做同时也可以克服类似这样的corner case,intervals = [[1, 2]], newInterval = [4, 5]。实际两者是没有交集的,但是有了这个while,就可以确保[4, 5]也被加入结果集。
  • 遍历剩下的intervals,无条件加入结果集,因为他们跟newInterval一定也没有交集。如何知道我可以开始遍历剩下的intervals了呢?把这个条件取反即可,intervals[i][0] <= newInterval[1],得到intervals[i][0] > newInterval[1],也就是某一个subinterval的开始已经大于要merge的interval的右边界了,这时如果还没遍历完,剩下的subinterval就可以直接加入结果集了。

时间O(n)

空间O(n)

JavaScript实现

 1 /**
 2  * @param {number[][]} intervals
 3  * @param {number[]} newInterval
 4  * @return {number[][]}
 5  */
 6 var insert = function(intervals, newInterval) {
 7     // corner case
 8     if (newInterval === null) {
 9         return intervals;
10     }
11 
12     // normal case
13     let res = [];
14     let i = 0;
15     // all the intervals before newInterval
16     while (i < intervals.length && intervals[i][1] < newInterval[0]) {
17         res.push(intervals[i]);
18         i++;
19     }
20 
21     // compare newInterval with the interval might overlap
22     while (i < intervals.length && intervals[i][0] <= newInterval[1]) {
23         newInterval[0] = Math.min(intervals[i][0], newInterval[0]);
24         newInterval[1] = Math.max(intervals[i][1], newInterval[1]);
25         i++;
26     }
27     res.push(newInterval);
28 
29     // all the intervals after newInterval
30     while (i < intervals.length) {
31         res.push(intervals[i]);
32         i++;
33     }
34     return res;
35 };

Java实现

 1 class Solution {
 2     public int[][] insert(int[][] intervals, int[] newInterval) {
 3         // corner case
 4         if (intervals == null) {
 5             return intervals;
 6         }
 7 
 8         // normal case
 9         int len = intervals.length;
10         List<int[]> res = new ArrayList<>();
11         int i = 0;
12         // intervals before
13         while (i < len && intervals[i][1] < newInterval[0]) {
14             res.add(intervals[i]);
15             i++;
16         }
17 
18         // merge current interval
19         while (i < len && intervals[i][0] <= newInterval[1]) {
20             newInterval[0] = Math.min(newInterval[0], intervals[i][0]);
21             newInterval[1] = Math.max(newInterval[1], intervals[i][1]);
22             i++;
23         }
24         res.add(newInterval);
25 
26         // intervals after
27         while (i < len) {
28             res.add(intervals[i]);
29             i++;
30         }
31         return res.toArray(new int[res.size()][]);
32     }
33 }

扫描线相关题目

LeetCode 题目总结

原文地址:https://www.cnblogs.com/cnoodle/p/11775931.html