56.合并区间(双指针+排序)
问题:以数组 intervals
表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]
。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。
思路:一开始没想到对二维数组进行排序,看了题解之后才知道这个排序方法
若我们对这个二维数组按照左端点进行排序,那么可以合并的区间一定是相邻的。
定义cur
和pre
两个指针分别指向当前区间和前一个区间。定义list
来存储当前可以合并的区间。
- 若
pre区间
(pre
指向的区间)的右端点
大于等于cur
区间的左端点
,则说明这两个区间是可以合并的。合并当前区间并赋值给pre
区间,cur
指针后移。因为不知道后面的区间还能不能和合并后的区间再合并,所以并没有将当前的pre
区间放入list
中。其实也可以合并后再放入,然后下一次循环取出来list中的最后一个区间作为pre
区间,再比较。 - 否则这两个区间不能合并。
将合并后的pre区间放入list中
,并指向cur区间。
需要注意的是,所有循环完之后,需要将最后一个pre
区间放入list
中。假设cur
指向给定区间集合的最后一个区间
- 若
pre
区间和cur
区间可以合并,则合并完之后就结束循环了,并没有将pre
区间放入list
中 - 若
pre
区间和cur
区间不能合并,则会将前一个合并的区间放入list
中,cur
区间并没有被放入list
中。
接下来证明一下这个条件:若pre区间
的右端点
大于等于cur
区间的左端点
,则说明这两个区间是可以合并的。因为给定的区间集合按照每个区间的左端点排过序了,当区间pre
的右端点大于等于当前区间cur
的左端点,即pre[1] >= cur[0]
。这意味着pre
的右端点可能落在cur
区间中,也有可能落在cur
区间右侧,但是pre
的左端点始终小于等于cur
区间的左端点(因为排过序),所以无论如何这两个区间都会有交集,即肯定可以合并。
class Solution {
public int[][] merge(int[][] intervals) {
int n = intervals.length;
if(n < 2) return intervals;
Arrays.sort(intervals, new Comparator<int[]>() {
public int compare(int[] interval1, int[] interval2) {
return interval1[0] - interval2[0];
}
});
//lambada表达式 效果等于上面的语句
Arrays.sort(intervals, (i1, i2) -> i1[0] - i2[0]);
List<int[]> list = new ArrayList();
int[] pre = intervals[0];
for(int i = 1; i < n; i++){
int[] cur = intervals[i];
if(pre[1] >= cur[0]) {
pre[1] = Math.max(pre[1], cur[1]);
pre[0] = Math.min(pre[0], cur[0]);
} else {
list.add(new int[]{pre[0], pre[1]});
pre = cur;
}
}
list.add(new int[]{pre[0], pre[1]});
return list.toArray(new int[0][0]);
}
}
总结思路,以便复习,如有错误,望指正。