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 }