题目
标题和出处
标题:删除被覆盖区间
难度
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} c≤a 且 b ≤ d \texttt{b} \le \texttt{d} b≤d 时,区间 [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} 1≤intervals.length≤1000
- 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} 0≤li≤ri≤105
- 所有的区间各不相同
解法
思路和算法
为了删除数组 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)。