合并区间

题目介绍

力扣56题:https://leetcode-cn.com/problems/merge-intervals/

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

分析

要判断两个区间[a1, b1], [a2, b2]是否可以合并,其实就是判断是否有a1 <= a2 <= b1,或者a2 <= a1 <= b2。也就是说,如果某个子区间的左边界在另一子区间内,那么它们可以合并。

解决方法:排序

一个简单的想法是,我们可以遍历每一个子区间,然后判断它跟其它区间是否可以合并。如果某两个区间可以合并,那么就把它们合并之后,再跟其它区间去做判断。很明显,这样的暴力算法,时间复杂度不会低于O(n^2)。有没有更好的方式呢?

这里我们发现,判断区间是否可以合并的关键,在于它们左边界的大小关系。所以我们可以先把所有区间,按照左边界进行排序。

那么在排完序的列表中,可以合并的区间一定是连续的。如下图所示,标记为蓝色、黄色和绿色的区间分别可以合并成一个大区间,它们在排完序的列表中是连续的:
在这里插入图片描述
代码演示如下:

public class MergeIntervals {
    public int[][] merge(int[][] intervals) {
        List<int[]> result = new ArrayList<int[]>();
        // 先对原数组按左边界排序
        Arrays.sort(intervals, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[0] - o2[0]; 
            }
        });
        // 遍历排序后的数组,逐个判断合并
        for ( int[] interval: intervals ){
            int left = interval[0], right = interval[1];
            int length = result.size();
            if ( length == 0 || left > result.get(length - 1)[1] ){
                result.add(interval);
            } else {
                int mergedLeft = result.get(length - 1)[0];
                int mergedRight = Math.max( result.get(length - 1)[1], right );
                result.set( length - 1, new int[]{mergedLeft, mergedRight} );
            }
        }
        return result.toArray(new int[result.size()][]);
    }
}

复杂度分析

  • 时间复杂度:O(nlogn),其中 n 为区间的数量。除去排序的开销,我们只需要一次线性扫描,所以主要的时间开销是排序的O(nlogn)。
  • 空间复杂度:O(logn),其中 n 为区间的数量。O(logn) 即为快速排序所需要的空间复杂度(递归栈深度)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值