夯实算法-合并区间

142 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的27天,点击查看活动详情

题目:LeetCode

以数组 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<=1041 <= intervals.length <= 10^4
  • intervals[i].length == 2
  • 0<=starti<=endi<=1040 <= starti <= endi <= 10^4

解题思路

分析题意可以用排序加二分查找。以区间开始值作为主键来排序和查找。

用一个集合来保存结果,这个集合里面的所有的区间都是不重叠的。

新来一个区间时inter,在结果集合中找到它的left,也就是left[0]<=inter[0], 以及找到right,也就是right[0]>=inter[0]。

有几种情况,当inter与left和right都不重叠时,就要把inter直接加入到集合中。

仅与left有重叠时,就与left合并,把left移除,加入合并后的区间。

仅与right有重叠时,移除right,加入合并后的区间。

如果与left和right都有重叠时,把left, right都移除,然后加入合并后的区间。

这里的集合,用TreeMap比较合适。TreeMap能做到查删加都是log(n)的,所以整体时间复杂度是在O(nlogn)。

如果用数组代替TreeMap,二分查找能做到log(n),但添加和删除只能到O(n),整体会逊于TreeMap。

代码实现

public int[][] merge(int[][] intervals) {
    Arrays.sort(intervals, (a, b) -> a[0] - b[0]);

    TreeMap < Integer, Integer > map = new TreeMap < > ();

    for (int[] in : intervals) {
        Map.Entry < Integer, Integer > floor = map.floorEntry( in [0]);
        Map.Entry < Integer, Integer > ceil = map.ceilingEntry( in [0]);
        // not intersect with floor
        boolean offFloor = floor == null || floor.getValue() < in [0];
        // not intersect with ceil
        boolean offCeil = ceil == null || ceil.getKey() > in [1];
        if (offFloor && offCeil) {
            map.put( in [0], in [1]);
        } else if (!offFloor && !offCeil) {
            // merge with floor and ceil
            map.remove(floor.getKey());
            map.remove(ceil.getKey());
            map.put(floor.getKey(), Math.max(ceil.getValue(), in [1]));
        } else if (!offFloor) {
            // merge with floor
            map.remove(floor.getKey());
            map.put(floor.getKey(), Math.max( in [1], floor.getValue()));
        } else if (!offCeil) {
            // merge with ceil
            map.remove(ceil.getKey());
            map.put( in [0], Math.max( in [1], ceil.getValue()));
        }
    }

    int[][] result = new int[map.size()][2];
    int index = 0;
    for (Map.Entry < Integer, Integer > entry: map.entrySet()) {
        result[index] = new int[] {
            entry.getKey(), entry.getValue()
        };
        index++;
    }

    return result;
}

运行结果

Snipaste_2022-12-24_23-01-06.png

复杂度分析

  • 空间复杂度:O(n)O(n)
  • 时间复杂度:O(nlogn)O(nlogn)

掘金(JUEJIN)  一起分享知识, Keep Learning!