leetcode 056: 合并区间
以数组 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
Related Topics
数组
排序
思路1 : 排序加暴力破解
public int[][] merge(int[][] intervals) { int[] flag = new int[intervals.length]; HashMap<Integer,Integer> map = new HashMap<>(); //对区间排序 插入排序 for(int i = 1 ; i < intervals.length;i++){ for(int j = i; j > 0 && intervals[j][0] < intervals[j-1][0]; j --){ int[] temp = intervals[j]; intervals[j] = intervals[j-1]; intervals[j-1] = temp; } } for(int i = 0; i < intervals.length;i++){ //表示i已经并合并 if(flag[i] == 1){ continue; } flag[i] = 1; for(int j = i + 1; j < intervals.length;j++){ if(flag[j] == 1){ continue; } //判断是否需要合并 //当i的左边界大于j的右边界 i的右边界小于j的左边界 不需要合并 if(intervals[i][0] > intervals[j][1] || intervals[i][1] < intervals[j][0]){ }else{ if(intervals[i][0] > intervals[j][0]){ intervals[i][0] = intervals[j][0]; } if(intervals[i][1] < intervals[j][1]){ intervals[i][1] = intervals[j][1]; } flag[j] = 1; } } //此时i里面存储的最终合并的结果 map.put(intervals[i][0],intervals[i][1]); } int[][] result = new int[map.size()][2]; int index = 0; for (Map.Entry<Integer, Integer> entry : map.entrySet()) { result[index][0] = entry.getKey(); result[index][1] = entry.getValue(); index++; } return result; } 执行耗时:297 ms,击败了5.17% 的Java用户 内存消耗:45.8 MB,击败了5.02% 的Java用户
对上面的思路进行优化,因为已经排序过 ,当无法合并的时候,后续也不需要判断。
跟上面比起来,性能虽然提升很大,但还是相对较差。
public int[][] merge(int[][] intervals) { HashMap<Integer,Integer> map = new HashMap<>(); //对区间排序 插入排序 for(int i = 1 ; i < intervals.length;i++){ for(int j = i; j > 0 && intervals[j][0] < intervals[j-1][0]; j --){ int[] temp = intervals[j]; intervals[j] = intervals[j-1]; intervals[j-1] = temp; } } for(int i = 0; i < intervals.length;i++){ //因为已经排序过 所以 当j的左边界大于i的右边界时 后面的就无需判断 int j; for(j = i + 1; j < intervals.length && intervals[i][1] >= intervals[j][0];j++){ if(intervals[i][1] < intervals[j][1]){ intervals[i][1] = intervals[j][1]; } } //[i,j)范围内已合并完毕 //此时i里面存储的最终合并的结果 map.put(intervals[i][0],intervals[i][1]); i = j-1; } int[][] result = new int[map.size()][2]; int index = 0; for (Map.Entry<Integer, Integer> entry : map.entrySet()) { result[index][0] = entry.getKey(); result[index][1] = entry.getValue(); index++; } return result; } 解答成功: 执行耗时:172 ms,击败了5.17% 的Java用户 内存消耗:45.9 MB,击败了5.02% 的Java用户
使用jdk提供的排序算法进行优化,性能有了明显的提升。
public int[][] merge(int[][] intervals) { //排序 由于自己写的插入排序相比jdk中的排序算法性能相对较差 使用arrays中的sort排序 HashMap<Integer,Integer> map = new HashMap<>(); Arrays.sort(intervals, new Comparator<int[]>() { @Override public int compare(int[] o1, int[] o2) { return o1[0]-o2[0]; } }); for(int i = 0; i < intervals.length;i++){ //因为已经排序过 所以 当j的左边界大于i的右边界时 后面的就无需判断 int j; for(j = i + 1; j < intervals.length && intervals[i][1] >= intervals[j][0];j++){ if(intervals[i][1] < intervals[j][1]){ intervals[i][1] = intervals[j][1]; } } //[i,j)范围内已合并完毕 //此时i里面存储的最终合并的结果 map.put(intervals[i][0],intervals[i][1]); i = j-1; } int[][] result = new int[map.size()][2]; int index = 0; for (Map.Entry<Integer, Integer> entry : map.entrySet()) { result[index][0] = entry.getKey(); result[index][1] = entry.getValue(); index++; } return result; }
思路2:参考leetcode
public int[][] merge(int[][] intervals) { Arrays.sort(intervals, new Comparator<int[]>() { @Override public int compare(int[] o1, int[] o2) { return o1[0]-o2[0]; } }); ArrayList<int[]> list = new ArrayList<>(); for(int i = 0 ;i < intervals.length;i++){ int left = intervals[i][0]; int right = intervals[i][1]; //如果当前的左边界大于合并中最后一个的右边界 说明不需要合并 if(list.size() == 0 || left > list.get(list.size() - 1)[1]){ list.add(new int[]{left,right}); }else{//需要合并 list.get(list.size()-1)[1] = Math.max(list.get(list.size()-1)[1],right); } } return list.toArray(new int[list.size()][]);