【435. 无重叠区间 中等】
题目:
给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。
注意 只在一点上接触的区间是 不重叠的。例如 [1, 2] 和 [2, 3] 是不重叠的。
示例 1:
输入: intervals = [[1,2],[2,3],[3,4],[1,3]]
输出: 1
解释: 移除 [1,3] 后,剩下的区间没有重叠。
示例 2:
输入: intervals = [ [1,2], [1,2], [1,2] ]
输出: 2
解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。
示例 3:
输入: intervals = [ [1,2], [2,3] ]
输出: 0
解释: 你不需要移除任何区间,因为它们已经是无重叠的了。
提示:
- 1 <= intervals.length <= 105
- intervals[i].length == 2
- -5 * 104 <= starti < endi <= 5 * 104
思路:
这道题有两个思路:
- 记录重叠区间个数,重叠区间个数就是最小移除次数
- 记录非交叉区间个数,最小移除次数 = 区间总数 - 非交叉区间个数
看到这道题目都冥冥之中感觉要排序,但是究竟是按照右边界排序,还是按照左边界排序呢?
其实都可以。主要就是为了让区间尽可能的重叠。
这里按照右边界排序。
针对思路2,记录非交叉区间的个数还是有技巧的,如图:
区间,1,2,3,4,5,6都按照右边界排好序。
当确定区间 1 和 区间2 重叠后,如何确定是否与 区间3 也重贴呢?
就是取 区间1 和 区间2 右边界的最小值,因为这个最小值之前的部分一定是 区间1 和区间2 的重合部分,如果这个最小值也触达到区间3,那么说明 区间 1,2,3都是重合的。
接下来就是找大于区间1结束位置的区间,是从区间4开始。那有同学问了为什么不从区间5开始?别忘了已经是按照右边界排序的了。
区间4结束之后,再找到区间6,所以一共记录非交叉区间的个数是三个。
总共区间个数为6,减去非交叉区间的个数3。移除区间的最小数量就是3。
代码:
- 思路一
class Solution {
public:
// 按照右边界排序
static bool cmp(vector<int>& a, vector<int>& b){
return a[1] < b[1];
}
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
if(intervals.size() == 0) return 0;
sort(intervals.begin(), intervals.end(), cmp);
int result = 0; // 记录重叠区间的个数
for(int i = 1; i < intervals.size(); i++){
if(intervals[i][0] < intervals[i - 1][1]){ // 如果重叠
intervals[i][1] = min(intervals[i - 1][1], intervals[i][1]); // 更新区间分割点
result++; // 重叠区间个数加一
}
}
return result; // 重叠区间个数就是最小移除次数
}
};
- 思路二
class Solution {
public:
// 按照右边界排序
static bool cmp(vector<int>& a, vector<int>& b){
return a[1] < b[1];
}
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
if(intervals.size() == 0) return 0;
sort(intervals.begin(), intervals.end(), cmp);
int count = 1; // 记录非交叉区间的个数
int end = intervals[0][1]; // 记录区间分割点
for(int i = 1; i < intervals.size(); i++){
if(end <= intervals[i][0]){ // 如果不交叉
end = intervals[i][1]; // 更新区间分割点
count++; // 非交叉区间个数加一
}
}
return intervals.size() - count; // 最小移除次数 = 区间个数 - 非交叉区间的个数
}
};
总结:
时间复杂度:O(nlog n) ,有一个快排
空间复杂度:O(n),有一个快排,最差情况(倒序)时,需要n次递归调用。因此确实需要O(n)的栈空间
参考:
代码随想录