这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战
题目
1288. 删除被覆盖区间
给你一个区间列表,请你删除列表中被其他区间所覆盖的区间。
只有当 c <= a 且 b <= d 时,我们才认为区间 [a,b) 被区间 [c,d) 覆盖。
在完成所有删除操作后,请你返回列表中剩余区间的数目。
示例:
输入: intervals = [[1,4],[3,6],[2,8]]
输出: 2
解释: 区间 [3,6] 被区间 [2,8] 覆盖,所以它被删除了。
提示:
1 <= intervals.length <= 10000 <= intervals[i][0] < intervals[i][1] <= 10^5- 对于所有的
i != j:intervals[i] != intervals[j]
思路
- 对所有区间进行排序,按照左边界的先后位置进行排序,这样子后面的元素就不用比较左边界了,直接比较右边界即可;
- 遍历数组,判断当前的右边界在之前出现的区间中有没有被覆盖过,如果有的话说明这个区间整个是无效区间,因为前面的元素左边界肯定覆盖当前元素的左边界了,如果右边界也覆盖说明当前区间是个子区间,这时候区间数量减一,表示删除了当前区间;
- 遍历结束后,返回当前的区间的剩余数量即可。
实现
/**
* @param {number[][]} intervals
* @return {number}
*/
var removeCoveredIntervals = function(intervals) {
// 按左边界进行排序,同时右边界越大越好
intervals.sort((a, b) => {
if (a[0] === b[0]) {
return b[1] - a[1];
}
return a[0] - b[0];
});
// 记录所有的区间数量,如果有无效区间则数量 - 1;
let result = intervals.length;
// 遍历每个区间判断是否有效
for (let i = 1; i < intervals.length; i++) {
// 由于左边界已经排序过了,我们比较右边界有没有被覆盖过即可
for (let j = 0; j < i; j++) {
if (intervals[j][1] >= intervals[i][1]) {
result--;
break;
}
}
}
return result;
};
贪心优化
- 实际上我们排序完,前面元素的左边界肯定是覆盖了当前元素的左边界了,我们没必要跑双重循环去比较之前有没有大于这个元素的右边界,只需要在每一轮跑完的时候记录一下我们所拥有的最大右边界即可;
- 然后我们遍历的时候,只需要判断上一轮的右边界是否比当前的右边界小即可,如果是的话,重新定义最大的右边界,同时当前的有效区间数量+1;
- 如果当前的右边界小于等于之前记录的,说明之前的区间已经囊括了当前区间,那么不用做任何操作;
- 最终一轮遍历结束后返回我们记录的有效区间数量即可。
实现
/**
* @param {number[][]} intervals
* @return {number}
*/
var removeCoveredIntervals = function(intervals) {
// 按左边界进行排序,同时右边界越大越好
intervals.sort((a, b) => a[0] - b[0] || b[1] - a[1]);
// 记录有效的数量
let result = 0;
// 记录所走过的最大的右边界
let right = 0;
for (let i = 0; i < intervals.length; i++) {
// 排序后,左边界已经肯定是依次递增了,判断右边界的位置即可
if (right < intervals[i][1]) {
result++;
right = intervals[i][1];
}
}
return result;
};
最终结果
看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。