排序题目:删除被覆盖区间

题目

标题和出处

标题:删除被覆盖区间

出处:1288. 删除被覆盖区间

难度

5 级

题目描述

要求

给你一个区间列表,请你删除列表中被其他区间所覆盖的区间。

给定区间数组 intervals \texttt{intervals} intervals,其中 intervals[i]   =   [l i ,   r i ] \texttt{intervals[i] = [l}_\texttt{i}\texttt{, r}_\texttt{i}\texttt{]} intervals[i] = [li, ri] 表示区间 [l i ,   r i ) \texttt{[l}_\texttt{i}\texttt{, r}_\texttt{i}\texttt{)} [li, ri),删除所有被其他区间所覆盖的区间。

当且仅当 c ≤ a \texttt{c} \le \texttt{a} ca b ≤ d \texttt{b} \le \texttt{d} bd 时,区间 [a,   b) \texttt{[a, b)} [a, b) 被区间 [c,   d) \texttt{[c, d)} [c, d) 覆盖。

返回剩余区间的数目。

示例

示例 1:

输入: intervals   =   [[1,4],[3,6],[2,8]] \texttt{intervals = [[1,4],[3,6],[2,8]]} intervals = [[1,4],[3,6],[2,8]]
输出: 2 \texttt{2} 2
解释:区间 [3,6] \texttt{[3,6]} [3,6] 被区间 [2,8] \texttt{[2,8]} [2,8] 覆盖,所以被删除。

示例 2:

输入: intervals   =   [[1,4],[2,3]] \texttt{intervals = [[1,4],[2,3]]} intervals = [[1,4],[2,3]]
输出: 1 \texttt{1} 1

数据范围

  • 1 ≤ intervals.length ≤ 1000 \texttt{1} \le \texttt{intervals.length} \le \texttt{1000} 1intervals.length1000
  • intervals[i].length = 2 \texttt{intervals[i].length} = \texttt{2} intervals[i].length=2
  • 0 ≤ l i ≤ r i ≤ 10 5 \texttt{0} \le \texttt{l}_\texttt{i} \le \texttt{r}_\texttt{i} \le \texttt{10}^\texttt{5} 0liri105
  • 所有的区间各不相同

解法

思路和算法

为了删除数组 intervals \textit{intervals} intervals 中的所有被其他区间覆盖的区间,需要首先将所有的区间排序,然后判断每个区间是否被其他区间覆盖,计算没有被其他区间覆盖的区间个数。

对区间排序的方法是,首先将区间按照开始位置升序排序,如果存在多个区间的开始位置相同,则按照结束位置降序排序。排序之后,相同开始位置的多个区间中,第一个区间是最长的区间,其余的每个区间都是被覆盖的区间。

遍历排序后的数组 intervals \textit{intervals} intervals,由于区间按照开始位置升序排序,因此后面遍历到的区间的开始位置一定不会小于前面遍历到的区间的开始位置。遍历的过程中维护没有被其他区间覆盖的区间个数和区间的最大结束位置 end \textit{end} end。由于数组 intervals \textit{intervals} intervals 中至少有 1 1 1 个区间,因此初始时没有被其他区间覆盖的区间个数是 1 1 1 end \textit{end} end 为首个区间(即 intervals [ 0 ] \textit{intervals}[0] intervals[0])的结束位置。遍历其余的区间时,执行如下操作。

  • 如果当前区间的结束位置大于 end \textit{end} end,则已经遍历过的区间的结束位置都小于当前区间的结束位置,因此当前区间没有被覆盖,后面的区间也不可能覆盖当前区间(后面区间的开始位置一定大于等于当前区间的开始位置,且当开始位置相等时后面区间的结束位置一定小于当前区间的结束位置),因此将没有被其他区间覆盖的区间个数加 1 1 1,将 end \textit{end} end 更新为当前区间的结束位置。

  • 如果当前区间的结束位置小于等于 end \textit{end} end,则已经遍历过的区间中至少存在一个区间的结束位置是 end \textit{end} end,且已经遍历过的区间的开始位置都小于等于当前区间的开始位置,因此一定存在一个结束位置是 end \textit{end} end 的区间覆盖当前区间,即当前区间被覆盖。

遍历结束之后,即可得到没有被其他区间覆盖的区间个数。

代码

class Solution {
    public int removeCoveredIntervals(int[][] intervals) {
        Arrays.sort(intervals, (a, b) -> {
            if (a[0] != b[0]) {
                return a[0] - b[0];
            } else {
                return b[1] - a[1];
            }
        });
        int length = intervals.length;
        int count = 1;
        int end = intervals[0][1];
        for (int i = 1; i < length; i++) {
            if (intervals[i][1] > end) {
                count++;
                end = Math.max(end, intervals[i][1]);
            }
        }
        return count;
    }
}

复杂度分析

  • 时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn),其中 n n n 是数组 intervals \textit{intervals} intervals 的长度。排序需要 O ( n log ⁡ n ) O(n \log n) O(nlogn) 的时间,排序后遍历数组需要 O ( n ) O(n) O(n) 的时间,时间复杂度是 O ( n log ⁡ n ) O(n \log n) O(nlogn)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 intervals \textit{intervals} intervals 的长度。由于排序的元素是数组,因此 Java 自带的 Arrays.sort \texttt{Arrays.sort} Arrays.sort 方法使用归并排序,空间复杂度是 O ( n ) O(n) O(n)

  • 21
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值