• [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 题目总结

  • 相关阅读:
    C++设计模式-Adapter适配器模式
    创业进行时之用户注册
    毕业三年
    献给在这个世界上摇摆不定的朋友们
    调用一个系统命令,并读取它的输出值(使用QProcess.readAll)
    Delphi自写组件:可设置颜色的按钮(改成BS_OWNERDRAW风格,然后CN_DRAWITEM)
    Delphi透明组件开发(去掉自己的csOpaque,去掉父控件的WS_CLIPCHILDREN,增加WS_EX_TRANSPARENT,截获WM_ERASEBKGND,然后在WM_DRAWITEM里画) good
    读一读Scktsrvr.exe的源程序
    窗口显示于parent控件上(用到了ManualDock函数)
    终于说再见了!Google Reader
  • 原文地址:https://www.cnblogs.com/cnoodle/p/11775931.html
Copyright © 2020-2023  润新知