以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
题目地址:https://leetcode.cn/problems/merge-intervals
作者:本人
思路
现将二维数组按照内层数组的第一个元素的大小进行排列(从小到大),这样方便我们讨论合并的情况。
遍历每个数组进行判断,符合合并就向后覆盖,不符合合并就复制
排序之后,需要合并的结果就只有两种:
一. [ 1 , 4 ] , [ 2 , 3 ] 合并为 [ 1 , 4 ]
二. [ 1 , 3 ] , [ 2 , 4 ] 合并为 [ 1 , 4 ]
只需要做简单的if判断即可。
不需要合并的时候,直接复制到结果数组
合并的方法:向后覆盖,也就是将合并的结果 直接覆盖到后一个一维数组上
例如 [ 1 , 4 ] , [ 2 , 3 ] 覆盖为 [ 1 , 4 ] , [ 1 , 4 ]。
[ 1 , 3 ] , [ 2 , 4 ] 覆盖为 [ 1 , 3 ] , [ 1 , 4 ]。
代码
class Solution {
public int[][] merge(int[][] intervals) {
sort(intervals);//先按照内层数组的第一个元素进行排序
int len = intervals.length;
int arr[][] = new int[len][2];
int a = 0;
for (int i = 0; i < len; i++) {
if (i == len - 1) {//如果走到最后一个元素了,那就别判断了,直接复制过去
arr[a][0] = intervals[i][0];
arr[a][1] = intervals[i][1];
a++;
break;
}
if (intervals[i][1] >= intervals[i + 1][1]){//需要合并,合并的方式是 第一种方式
intervals[i+1][0] = intervals[i][0];
intervals[i+1][1] = intervals[i][1];
}else {
if (intervals[i][1] >= intervals[i + 1][0]) {//需要合并,合并的方式是 第二种方式
intervals[i+1][0] = intervals[i][0];
intervals[i+1][1] = intervals[i + 1][1];
} else {//不需要合并
arr[a][0] = intervals[i][0];
arr[a][1] = intervals[i][1];
a++;
}
}
}
int res[][] = new int[a][2];
for (int i = 0; i < a; i++) {
res[i][0] = arr[i][0];
res[i][1] = arr[i][1];
}
return res;
}
//按照内层数组的第一个元素进行排序
int[][] sort(int arr[][]) {
int len = arr.length;
for (int j = 0; j < len; j++) {
for (int i = 0; i < len - 1; i++) {
if (arr[i][0] > arr[i + 1][0]) {//交换位置
int a0 = arr[i][0];
int a1 = arr[i][1];
arr[i][0] = arr[i + 1][0];
arr[i][1] = arr[i + 1][1];
arr[i + 1][0] = a0;
arr[i + 1][1] = a1;
}
}
}
return arr;
}
}
效果
我写的这个方法,不是很好的方法
看了网上的代码,别人进行排序时,是直接调用java.sort的方法,效率比我这个自己写的冒泡法好多了。
优化1:将自己写的排序 改为 java提供的排序
对二维数组intervals,按照内层数组的第一个元素进行排序
Arrays.sort(intervals, new Comparator() {
public int compare(int[] interval1, int[] interval2) {
return interval1[0] - interval2[0];
}
});
时间复杂度上会提高很多
优化2:部分数组复制
我是自己写的复制,别人是调用java提供的Arrays.copyOfRange 这个方法
这个应该优化不了什么,只是让代码简短些
return Arrays.copyOfRange(arr, 0, a);//注意这个拷贝数组的方法是前闭后开
最终优化后的方法一
class Solution {
public int[][] merge(int[][] intervals) {
//对数组按照内层数组的第一个元素进行排序
Arrays.sort(intervals, new Comparator() {
public int compare(int[] interval1, int[] interval2) {
return interval1[0] - interval2[0];
}
});
int len = intervals.length;
int arr[][] = new int[len][2];
int a = 0;
for (int i = 0; i < len; i++) {
if (i == len - 1) {//如果走到最后一个元素了,那就别判断了,直接复制过去
arr[a][0] = intervals[i][0];
arr[a][1] = intervals[i][1];
a++;
break;
}
if (intervals[i][1] >= intervals[i + 1][1]){//需要合并,合并的方式是 第一种方式
intervals[i+1][0] = intervals[i][0];
intervals[i+1][1] = intervals[i][1];
}else {
if (intervals[i][1] >= intervals[i + 1][0]) {//需要合并,合并的方式是 第二种方式
intervals[i+1][0] = intervals[i][0];
intervals[i+1][1] = intervals[i + 1][1];
} else {//不需要合并
arr[a][0] = intervals[i][0];
arr[a][1] = intervals[i][1];
a++;
}
}
}
return Arrays.copyOfRange(arr, 0, a);//注意这个拷贝数组的方法是前闭后开
}
}
效果
时间复杂度优化了不少,java提供的这个排序还是比我自己写的冒泡排序好的多
作者
https://leetcode.cn/problems/merge-intervals/solution/merge-intervals-by-ikaruga/
思路
也是先排序,但区别是
方法1是遍历每个数组进行判断,符合合并就向后覆盖,不符合合并就复制到结果中。
方法2是,用双指针:start 和 end ,如果符合合并条件,那就直接更新end ,不符合合并条件,就复制到结果中。
明显,方法2在思路上更优越点。
class Solution {
public static int[][] merge(int[][] intervals) {
if(intervals.length == 0){
return new int[][]{};
}
Arrays.sort(intervals,(a,b)->{return a[0]-b[0];});
int[][] res = new int[intervals.length][2];
int index = 0;
int start =intervals[0][0],end = intervals[0][1];
//下一个数组的起始值必须要小于上一个数组的最大值才能合并
for(int i = 1; i
效果上和方法1一样,只是这个方法在思路上更优越
1. 思路不难,但是代码不简单,要多练
2. 要熟练掌握java自带的 sort 方法
Arrays.sort(intervals, new Comparator() {
public int compare(int[] interval1, int[] interval2) {
return interval1[0] - interval2[0];
}
});
3. 要熟练掌握java自带的 拷贝数组的方法
return Arrays.copyOfRange(arr, 0, a);//注意这个拷贝数组的方法是前闭后开