56. 合并区间

给出一个区间的集合,请合并所有重叠的区间。

示例 1:

输入: intervals = [[1,3],[2,6],[8,10],[15,18]]
输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

示例 2:

输入: intervals = [[1,4],[4,5]]
输出: [[1,5]]
解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。
注意:输入类型已于2019年4月15日更改。 请重置默认代码定义以获取新方法签名。

提示:

intervals[i][0] <= intervals[i][1]

思路:排序 + 双指针

先将二维数组中的所有子区间按左边界从小到大排序。

然后遍历所有的子区间,维护两个数字,分别是当前合并区间的左边界和右边界,每次遍历时,判断当前合并的右边界是否小于下个小区间的左边界,如果小于的话,说明当前合并区间和下个小区间没有交集,将当前的左右边界作为一个区间的左右边界存入结果集中,并重置下个合并区间的左右边界为下个小区间的左右边界;如果当前合并区间的右边界大于等于下个小区间的左边界,说明当前合并区间和下个小区间有交集,把合并区间的右边界更新为 下个小区间的右边界和当前合并区间右边界中的较大值,从而让合并区间扩张。

最后还需要再将合并区间的左右边界添加到结果集中一次,因为循环中没有把最后一个合并区间添加到结果集中。

 1 class Solution {
 2     public int[][] merge(int[][] intervals) {
 3         if(intervals == null || intervals.length == 0){
 4             return new int[0][0];
 5         }
 6         // 将所有的区间按左区间大小从小到大排序
 7         Arrays.sort(intervals, new Comparator<int[]>(){
 8             public int compare(int[] a, int[] b){
 9                 return a[0] - b[0];
10             }
11         });
12         int leftBorder = intervals[0][0], rightBorder = intervals[0][1];
13         int len = intervals.length;
14         ArrayList<int[]> res = new ArrayList<>();
15         for(int i = 1; i < len; i++){
16             if(rightBorder < intervals[i][0]){  // 说明不可能和下个集合有交集
17                 //System.out.println(leftBorder + " " + rightBorder);
18                 res.add(new int[]{leftBorder, rightBorder});
19                 leftBorder = intervals[i][0];
20                 rightBorder = intervals[i][1];
21             }else{
22                 rightBorder = Math.max(rightBorder, intervals[i][1]);   // 说明有交集
23             }
24         }
25         res.add(new int[]{leftBorder, rightBorder});
26         return res.toArray(new int[res.size()][2]);
27     }
28 }

leetcode 执行用时:7 ms > 90.82%, 内存消耗:41 MB > 92.54%

复杂度分析:

时间复杂度:O(nlogn), n 为数组长度,时间花费主要分为两部分,一部分是排序,时间复杂度为O(nlogn), 接下来一次遍历的时间花费为O(n)。

空间复杂度:O(1), 如果不算上 res 这个结果列表的空间开销的话,那空间复杂度就是O(1)