1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public int[][] insert(int[][] intervals, int[] newInterval) {
List<int[]> result = new ArrayList<>();
int start = newInterval[0];
int end = newInterval[1];
int idx = 0;
while (idx < intervals.length && intervals[idx][1] < start) {
result.add(intervals[idx++]);
}

while (idx < intervals.length && intervals[idx][0] <= end) {
start = Math.min(start, intervals[idx][0]);
end = Math.max(end, intervals[idx][1]);
idx += 1;
}
result.add(new int[] { start, end });

while (idx < intervals.length && intervals[idx][0] > end) {
result.add(intervals[idx++]);
}
return listToArray(result);
}

private int[][] listToArray(List<int[]> list) {
int[][] array = new int[list.size()][2];
for (int i = 0; i < array.length; i++) {
array[i] = list.get(i);
}
return array;
}
}

这上面是clean and concise的解法. 首先是找和自己没有交集的intervals. 分两部分: 在自己前面的和在自己后面的. 其次找到那些和自己有交集的也就是和自己的那些intervals不管是他们的start或者是end落在咱们的interval之间的. 也就是和咱们有交集的. 此时咱们挨个遍历和咱们有交集的interval. 其中第一个和最后一个和咱们有交集的最重要. 因为他俩决定了咱们和这一堆intervals merge后的总interval的上界和下界. 大概思路就是这样, 比较直接.

一个interval和另一个interval有交集无非四种情况. A的end在B之中, A完全被包裹在B中, A的start在B中, B被完全包裹在A中. 再简化就分为包含和不完全包含的关系. 因此和newInterval有交集的intervals都可以和newInterval进行merge. 若只有一个, 那么好说也就是看谁的start更小, 谁的end更大. 若有多个, 合并后的start由最靠左的那个interval决定. 要么是它的start要么就是newInterval的start当头. end则是最后一个interval决定, 要么它的end要么是newInterval的end作为结尾. 因为这些intervals都是按照从小到大顺序排好的而且互相没有交集.

时间复杂度: O(n)
空间复杂度: O(n)

以下是反面教材:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class Solution {
public int[][] insert(int[][] intervals, int[] newInterval) {
int newLeftBound = newInterval[0];
int newRightBound = newInterval[1];
int idx = 0;
List<int[]> result = new ArrayList<>();
while (idx < intervals.length) {
int currentIntervalLeftBound = intervals[idx][0];
int currentIntervalRightBound = intervals[idx][1];
if ((newLeftBound <= currentIntervalRightBound && newLeftBound >= currentIntervalLeftBound)
|| (newRightBound >= intervals[idx][0] && newRightBound <= intervals[idx][1])) {
intervals[idx][0] = Math.min(currentIntervalLeftBound, newLeftBound);
intervals[idx][1] = Math.max(currentIntervalRightBound, newRightBound);
break;
}
idx += 1;
}
if (idx == intervals.length) {
for (int[] interval : intervals) {
result.add(interval.clone());
}
result.add(newInterval.clone());
return arrayListToArray(result);
}

for (int i = 0; i <= idx; i++) {
result.add(intervals[i].clone());
}
idx += 1;
while (idx < intervals.length) {
int currentIntervalLeftBound = intervals[idx][0];
int currentIntervalRightBound = intervals[idx][1];
if (currentIntervalLeftBound <= result.get(result.size() - 1)[1]) {
result.get(result.size() - 1)[1] = Math.max(currentIntervalRightBound,
result.get(result.size() - 1)[1]);
} else {
result.add(intervals[idx].clone());
}
idx += 1;
}
return arrayListToArray(result);
}

public int[][] arrayListToArray(List<int[]> list) {
int[][] array = new int[list.size()][2];
for (int i = 0; i < list.size(); i++) {
array[i] = list.get(i);
}
return array;
}
}

我的思路是找到这个newInterval最先和哪个interval有交集, 然后和它合并, 合并完后从那里一直往后merge. 然而大问题就是newInterval不一定和某个interval是有交集的. 其次就是newInterval和interval的交集方式还有三种情况(体现在了第10 ,11行那么纠结的代码中). 我还认为只要和当前的interval没有交集就说明只可能和后面的有所交集, 如果没有一个有交集就说明这个newInterval必须被插到最后面. 这样的想法是因为我想当然了, 之前做了那个merge interval的题, 被那个思路影响了.