合并区间
原题链接:https://leetcode-cn.com/problems/merge-intervals/
一、问题描述
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。
示例 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] 可被视为重叠区间。
提示:
1 <= intervals.length <= 104
intervals[i].length == 2
0 <= starti <= endi <= 104
二、问题分析
如果我们能先对数组中所以区间的左端点按照从大到小的顺序进行排序,那么会减少很多操作。对于两个左端点有序的区间i和j,假设两个区间的左右端点都是left,right。那么如果i.right>=j.left,那么这两个区间就可以合并,合并后的区间应该取大区间,所以左端点应该取i.left,因为已经按照左端点进行了排序。右端点应该取两个区间中大的那个max(i.right,j.right)。这样两个区间就进行了合并,然后还应该拿这个合并后的区间和下一个区间进行比较,直到两个区间没有重叠部分为止,然后再比较后面的区间。
三、算法设计
需要一个新数组存放结果(可以不用,直接在原数组上进行修改,但是操作繁琐)
首先是对区间进行判断,重叠i.right>=j.left。不重叠i.right<j.left
区间合并,设新区间为n,n.left=i.left,n.right=max(i.right,j.right)
下面是指针的移动,定义一个结果数组n[0,0],定义一个指针fast遍历数组,遍历过程中如果n与遍历到的区间重叠就更新n,如果n与遍历到的区间不重叠就将n存入结果数组然后初始化,然后让fast向后移动。当fast遍历完数组的最后一个元素后结束循环返回结果。
四、代码
1 class Solution { 2 public int[][] merge(int[][] intervals) { 3 if (intervals.length == 0) { 4 return new int[0][2]; 5 } 6 Arrays.sort(intervals, new Comparator<int[]>() { 7 public int compare(int[] interval1, int[] interval2) { 8 return interval1[0] - interval2[0]; 9 } 10 }); 11 List<int[]> res = new ArrayList<int[]>();//定义结果数组用于返回结果 12 for(int fast=0;fast<intervals.length;fast++){ 13 int left=intervals[fast][0],right=intervals[fast][1]; 14 if(res.size()==0||res.get(res.size()-1)[1]<left){//如果结果数组大小为0,或者当前区间和上一个区间不重叠 15 res.add(new int[]{left, right}); 16 }else{//重叠 17 res.get(res.size()-1)[1]=Math.max(right,res.get(res.size()-1)[1]); 18 } 19 } 20 return res.toArray(new int[res.size()][]); 21 } 22 }
通过res.get(res.size()-1)可以取得上一个保存的数组,这样就不需要另外保存数组了,如果重叠就对上一个保存的数组直接进行修改即可,代码思想与算法设计有所不同,代码是先保存后修改,算法设计中是,先将重叠数组合并然后再保存。