【LeetCode-中等】56. 合并区间(详解)

题目

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

【LeetCode-中等】56. 合并区间(详解)_第1张图片

 题目地址:https://leetcode.cn/problems/merge-intervals

方法1:排序+向后覆盖

作者:本人

思路

现将二维数组按照内层数组的第一个元素的大小进行排列(从小到大),这样方便我们讨论合并的情况。

遍历每个数组进行判断,符合合并就向后覆盖,不符合合并就复制

排序之后,需要合并的结果就只有两种:

        一.  [ 1 , 4 ] , [ 2 , 3 ] 合并为 [ 1 , 4 ]

        二.  [ 1 , 3 ] , [ 2 , 4 ] 合并为 [ 1 , 4 ]

只需要做简单的if判断即可。

不需要合并的时候,直接复制到结果数组

合并的方法:向后覆盖,也就是将合并的结果 直接覆盖到后一个一维数组上

        例如 [ 1 , 4 ] , [ 2 , 3 ] 覆盖为  [ 1 , 4 ] , [ 1 , 4 ]。

                [ 1 , 3 ] , [ 2 , 4 ] 覆盖为 [ 1 , 3 ] , [ 1 , 4 ]。

代码

class Solution {
    public int[][] merge(int[][] intervals) {
        sort(intervals);//先按照内层数组的第一个元素进行排序
        int len = intervals.length;
        int arr[][] = new int[len][2];
        int a = 0;
        for (int i = 0; i < len; i++) {
            if (i == len - 1) {//如果走到最后一个元素了,那就别判断了,直接复制过去
                arr[a][0] = intervals[i][0];
                arr[a][1] = intervals[i][1];
                a++;
                break;
            }
            if (intervals[i][1] >= intervals[i + 1][1]){//需要合并,合并的方式是 第一种方式
                intervals[i+1][0] = intervals[i][0];
                intervals[i+1][1] = intervals[i][1];
            }else {
                if (intervals[i][1] >= intervals[i + 1][0]) {//需要合并,合并的方式是 第二种方式
                    intervals[i+1][0] = intervals[i][0];
                    intervals[i+1][1] = intervals[i + 1][1];
                } else {//不需要合并
                    arr[a][0] = intervals[i][0];
                    arr[a][1] = intervals[i][1];
                    a++;
                }
            }

        }
        int res[][] = new int[a][2];
        for (int i = 0; i < a; i++) {
            res[i][0] = arr[i][0];
            res[i][1] = arr[i][1];
        }

        return res;
    }

    //按照内层数组的第一个元素进行排序
    int[][] sort(int arr[][]) {
        int len = arr.length;
        for (int j = 0; j < len; j++) {
            for (int i = 0; i < len - 1; i++) {
                if (arr[i][0] > arr[i + 1][0]) {//交换位置
                    int a0 = arr[i][0];
                    int a1 = arr[i][1];
                    arr[i][0] = arr[i + 1][0];
                    arr[i][1] = arr[i + 1][1];
                    arr[i + 1][0] = a0;
                    arr[i + 1][1] = a1;
                }
            }
        }
        return arr;
    }
}

效果

我写的这个方法,不是很好的方法 

方法1:优化

看了网上的代码,别人进行排序时,是直接调用java.sort的方法,效率比我这个自己写的冒泡法好多了。

优化1:将自己写的排序 改为 java提供的排序

对二维数组intervals,按照内层数组的第一个元素进行排序

        Arrays.sort(intervals, new Comparator() {
            public int compare(int[] interval1, int[] interval2) {
                return interval1[0] - interval2[0];
            }
        });

时间复杂度上会提高很多

优化2:部分数组复制

我是自己写的复制,别人是调用java提供的Arrays.copyOfRange 这个方法

这个应该优化不了什么,只是让代码简短些

        return Arrays.copyOfRange(arr, 0, a);//注意这个拷贝数组的方法是前闭后开

最终优化后的方法一

class Solution {
    public int[][] merge(int[][] intervals) {
        //对数组按照内层数组的第一个元素进行排序
        Arrays.sort(intervals, new Comparator() {
            public int compare(int[] interval1, int[] interval2) {
                return interval1[0] - interval2[0];
            }
        });
        int len = intervals.length;
        int arr[][] = new int[len][2];
        int a = 0;
        for (int i = 0; i < len; i++) {
            if (i == len - 1) {//如果走到最后一个元素了,那就别判断了,直接复制过去
                arr[a][0] = intervals[i][0];
                arr[a][1] = intervals[i][1];
                a++;
                break;
            }
            if (intervals[i][1] >= intervals[i + 1][1]){//需要合并,合并的方式是 第一种方式
                intervals[i+1][0] = intervals[i][0];
                intervals[i+1][1] = intervals[i][1];
            }else {
                if (intervals[i][1] >= intervals[i + 1][0]) {//需要合并,合并的方式是 第二种方式
                    intervals[i+1][0] = intervals[i][0];
                    intervals[i+1][1] = intervals[i + 1][1];
                } else {//不需要合并
                    arr[a][0] = intervals[i][0];
                    arr[a][1] = intervals[i][1];
                    a++;
                }
            }

        }
        return Arrays.copyOfRange(arr, 0, a);//注意这个拷贝数组的方法是前闭后开
    }


}

效果

【LeetCode-中等】56. 合并区间(详解)_第2张图片

 时间复杂度优化了不少,java提供的这个排序还是比我自己写的冒泡排序好的多

方法2:排序+双指针

作者

https://leetcode.cn/problems/merge-intervals/solution/merge-intervals-by-ikaruga/

思路

也是先排序,但区别是

        方法1是遍历每个数组进行判断,符合合并就向后覆盖,不符合合并就复制到结果中。

        方法2是,用双指针:start 和 end ,如果符合合并条件,那就直接更新end ,不符合合并条件,就复制到结果中。

明显,方法2在思路上更优越点。

class Solution {
   public static int[][] merge(int[][] intervals) {
        if(intervals.length == 0){
            return new int[][]{};
        }
        Arrays.sort(intervals,(a,b)->{return a[0]-b[0];});
        int[][] res = new int[intervals.length][2];
        int index = 0;
        int start =intervals[0][0],end = intervals[0][1];
        //下一个数组的起始值必须要小于上一个数组的最大值才能合并
        for(int i = 1; i 

【LeetCode-中等】56. 合并区间(详解)_第3张图片 

 效果上和方法1一样,只是这个方法在思路上更优越

总结

1. 思路不难,但是代码不简单,要多练

2. 要熟练掌握java自带的 sort 方法

        Arrays.sort(intervals, new Comparator() {
            public int compare(int[] interval1, int[] interval2) {
                return interval1[0] - interval2[0];
            }
        });

3. 要熟练掌握java自带的 拷贝数组的方法

        return Arrays.copyOfRange(arr, 0, a);//注意这个拷贝数组的方法是前闭后开

你可能感兴趣的:(LeetCode刷题,leetcode,算法)