LeetCode系列之合并区间(字节面试题)题解

先看题目:
给出一个区间的集合,请合并所有重叠的区间。

示例 1:

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

示例 2:

输入: [[1,4],[4,5]]
输出: [[1,5]]
解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。

这里给出两种思路附加实现代码供参考:

  • 思路一:先排序,再比较相邻的区间是否能够合并,时间复杂度为:2*n方(假设有n段区间)
  • 思路二:直接比较相邻的区间是否能够合并,时间复杂度为:n方(假设有n段区间)

在解题之前,我们需要先弄清楚,任意两个区间之间存在哪些关系,也就是分类讨论的思想,图解如下:
在这里插入图片描述
清楚了上图描述的三种情况,我们就可以开始解题了:
解法一:

public int[][] merge(int[][] intervals) {
        List<int[]> res = new ArrayList<>();
        if (intervals == null || intervals.length == 0)
            return res.toArray(new int[0][]);

        // Arrays.sort(intervals, (a, b) -> a[0] - b[0]);// a[0] - b[0]大于0就交换顺序
        // 根据二维数组第一个数字大小按每一行整体排序
        Arrays.sort(intervals, new Comparator<int[]>() {  //根据数组和迭代器指定按照哪种规则进行排序
            @Override
            public int compare(int[] o1, int[] o2) {
                // TODO Auto-generated method stub
                return o1[0] - o2[0]; //>0就交换顺序,说明是按照升序排序
            }
        });

        int i = 0;
        while (i < intervals.length) {  //intervals.length = 行数
            int left = intervals[i][0];
            int right = intervals[i][1];
            // i不能到最后一行,所以要小于(数组的长度 - 1)
            // 判断所在行的right和下一行的left大小,对right重新进行赋最大值,之后再不断进行while循环判断
            while (i < intervals.length - 1 && right >= intervals[i + 1][0]) {
                i++;
                right = Math.max(right, intervals[i][1]);
            }
            res.add(new int[] { left, right });
            i++;
        }
        return res.toArray(new int[0][]);

    }

代码实现参考自leetcode讨论区,解释自己理解之后的思路:先排序,利用java集合的特性对所有区间进行排序,排序之后根据不同的情况是否合并区间,需要注意的是当出现需要合并的区间之后,下一次比较需要跳过一个区间,因为两个区间已经被合并成了一个,注意代码中的两处i++

时间复杂度为:O(2*n2) 空间复杂度:O(2n)

解法二:参考自leetcode提交区耗时为1ms的解法

public int[][] merge(int[][] intervals){
        if(intervals == null || intervals.length <= 1){
            return intervals;
        }
        int mergeCount = 0;
        for(int i = 0;i < intervals.length;i++){
            for(int j = i + 1; j <intervals.length; j++){
                if(intervals[i][1]>=intervals[j][0] && intervals[i][0]<=intervals[j][1]){
                    if(intervals[i][1]>intervals[j][1]){
                        intervals[j][1] = intervals[i][1];
                    }
                    if(intervals[i][0]<intervals[j][0]){
                        intervals[j][0] = intervals[i][0];
                    }
                    intervals[i] = null;
                    mergeCount++;
                    break;
                }
            }
        }
        int[][] result = new int[intervals.length - mergeCount][];
        for(int i = 0,j = 0;j < intervals.length;j++){
            if(intervals[j] != null){
                result[i++] =intervals[j];
            }
        }
        return result;
    }

具体实现就是结合上面图解的三种情况来分析,在比较分析的时候需要添加额外的判断条件,判断条件虽然复杂了许多,但是将时间复杂度优化了到了解法一的一半。

时间复杂度:O(n2) 空间复杂度:O(n)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值