这是我参与8月更文挑战的第19天,活动详情查看:8月更文挑战
题目
解法
我们希望一次性遍历目标数组就完成,这当然是最好的了,但考虑以下问题:
-
一旦发生了目标和结果中的合并,那么:
- 我们如何要对结果里的数据进行处理?
- 如果再次发生合并,是否我们还要再次进行相同的操作,直到本次没有再可以合并的了?
因此,我们将数据先按照第一个数(也就是左区间点)进行排序,这样子有几个好处:
-
因为排序过了,在进行比较的过程中就可以省略左区间的相互比较,取出来的目标数据的左区间,一定不小于结果的左区间。
-
也因为上面的关系,我们每次涉及到的结果数组,只需要考虑当前最后一个就可以了。因为:
- 我们的目标数组,要么和数组的最后一个相交(目标左<=结果右,此时合并进去。而且因为排序,我们只要进行这一次右端点的交换就可以了),要么就超过了数组最后一个区间的范围(目标左>结果右,此时我们在结果集里的最后面加一个)。
//我们希望在数轴上按照从前往后的顺序来排列,这样我们就不需要考虑合并的问题了
public static int[][] merge(int[][] intervals) {
if(intervals.length == 0) return new int[0][0];
//先排序
Arrays.sort(intervals, Comparator.comparingInt(o -> o[0]));
int[][] res = new int[intervals.length][];
res[0] = intervals[0];
int idx = 0;
for (int i = 1; i < intervals.length; i++) {
int l = intervals[i][0], r = intervals[i][1];
//因为排序过了,因此可以保证后面取出来的左边界数不小于前面的.我们只需要做两件事:
//1.输入区间,是否可以和当前区间合并?不可以的话,就添加到后面
//2.当前区间,是否可以扩展指定区间?
if(l>res[idx][1]){
idx++;
res[idx] = intervals[i];
}else{
res[idx][1] = Math.max(res[idx][1],r);
}
}
return Arrays.copyOf(res,idx+1);
}
执行用时:7 ms, 在所有 Java 提交中击败了63.91%的用户
内存消耗:40.8 MB, 在所有 Java 提交中击败了82.94%的用户
我们分析一下我们的时间复杂度:
- 排序O(NlogN)
- 循环处理O(N)
也就是说,我们的解法的时间复杂度实际上是由排序决定的。
\