题目:
给出一个区间的集合,请合并所有重叠的区间。
示例 1:
输入: [[1,3],[2,6],[8,10],[15,18]]
输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入: [[1,4],[4,5]]
输出: [[1,5]]
解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。
题目看起来还是挺简单的一个题目,就是要求并区间,数学里面我们都知道怎么做。
那如果对于示例 1 和示例 2 来说,当前一个区间的右端点 > 后一个的左端点, 就可以将这两个区间合并。
但是,示例的两个输入,区间的左端点是有序的,而实际输入可能是乱的。
所以这个问题就变成了,先要对原来的输入进行按照区间左端点的排序,再进行合并操作。
那么体现在实现层面,就是对二维数组的 intervals[x][0] 进行排序,之后再从头到尾遍历一遍,用 intervals[x][1] 和 intervals[y][0] 作比较。
(如果自己还是实现一个排序算法应该不是这个题目的重点?)
调用 Arrays.sort 算法的扩展操作:
Arrays.sort()方法的源码分析可以参考这篇博客:
浅谈Arrays.sort()原理
尤其当集合中的对象不支持自比较 或者 自比较的功能不能满足需求 时可以使用它来进行指定,比如说在一些实际应用里面:有一个学生类,包含一些信息,名单出来之后想按照他们的其中一个属性 语文成绩 排序这样的情况。
这里我们想要对二维数组进行排序,并且要指定排序的是这个二维数组里面的啥东西,所以要利用这个接口实现类来进行指定。
具体的使用方法如下:
对于一个一维数组:
int[] a={1,2,3,4,5}
我们本来调用Arrays.sort()方法的时候可以这样
Arrays.sort(a);
就完全可以了,表示对a数组进行排序,因为他里面的元素世界可以进行排序,是基本类型。
如果数组a是这样呢:
int[ ][ ] a= new int[ ][ ]{{1,3},{1,2},{4,5},{3,7}};
遇到这里的二维数组,这里面的每个元素是一个数组对象,没有实现Comparator接口,所以如果想要排序需要我们实现这个接口:
Arrays.sort(a,new Comparator<int[]>(){
@Override
public int compare(int[] a,int[] b){
return a[0]-b[0];
}
});
这段代码的功能就是,对于a数组进行排序,实现了一个 Comparator 接口。
也就是对二维数组排序的时候,按照里面每一个元素(是一个一位数组)的第一列元素进行比较。
这样的写法也可以进行简化成 Lambda 表达式:(java 8 之后支持的新特性)
Arrays.sort(arr,(a,b)->a[0]-b[0]);
表达的是和上面复写compare方法一样的意思:对于a和b的比较,比较a[0]和b[0]。
于是我们可以写出这道题目的代码:
class Solution {
public int[][] merge(int[][] intervals) {
//首先让区间左端点有序
Arrays.sort(intervals, (o1, o2) -> o1[0] - o2[0]);
int row=intervals.length;
int row1=intervals.length;
int i=0;
while(i<row){
int j=i+1;
while(j<row&&intervals[j][0]<=intervals[i][1]){
intervals[i][1]=intervals[j][1]>=intervals[i][1]?intervals[j][1]:intervals[i][1];
intervals[j][0]=Integer.MIN_VALUE;//为了方便被合并过的标记一下
intervals[j][1]=Integer.MIN_VALUE;
row1--;//记录答案的数组size,每合并一次就会少一个元素
j++;
}
i=j;//调到下一个没有被判断过的开始
}
//然后重新赋值返回答案
int[][] ans=new int[row1][2];
for(int j=0,k=0;j<row&&k<row1;j++){
if(intervals[j][0]>Integer.MIN_VALUE){
ans[k][0]=intervals[j][0];
ans[k][1]=intervals[j][1];
k++;
}
}
return ans;
}
}