题目:
给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠
注意:
- 可以认为区间的终点总是大于它的起点。
- 区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。
输入: [ [1,2], [2,3], [3,4], [1,3] ] 输出: 1 解释: 移除 [1,3] 后,剩下的区间没有重叠
这一题是一道典型的贪心算法;
这一题也让我认识到,不要拿到一题就开始分析例题中存在的数据特性,然后根据数据特点去死扣,以为能解出来,首先,拿到这一题,应该分析,什么样的区间会重叠,因为需要保留尽可能多的区间,从而我们应该怎么删除;
如果有两个区间x和y,如果x包含y,那么我们肯定选y,因为x可能包含了其他区间,从而选x会使得剩下的区间变少;
如果我们将区间按照右边端点排序b1<= b2 <=b3 ....
假设给你区间[a1, b1] 和 [a2, b2];
a1----------------------------------b1
a2--------------------------b2
很明显,这两段重合,如果放弃[a1, b1] ,则剩下的[a2, b2]很可能包含右边的区间,从而,我们应该删除[a2, b2];
即贪心策略是一定选择第一个区间,考虑了上面这种情况,还有如下的情况:
a1-------------------------b1
a2--------------------------------------b2
很明显, [a2, b2]很可能会包含左边的区间, 从而应该删除
所以只要考虑了尽量删除包含大的区间即可;因此我们只需要遍历一次就能够筛除重叠的区间;
第一次我使用了vector的erase;
从而时间复杂度大大增加,因为因为需要重新创建数组,因此下面给出了优化
class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
if(intervals.size()<2) return 0;
//sort with the most right of interval
sort(intervals.begin(),intervals.end(),[](const vector<int> &lhs,const vector<int> &rhs){
return lhs[1]<rhs[1];
});
int i=0;
int count=0;
while(i<intervals.size()-1)
{
auto cur=intervals[i];
auto next=intervals[i+1];
if(cur[1]==next[1]){
if(cur[0]<next[0]) intervals.erase(intervals.begin()+i+1);
else intervals.erase(intervals.begin()+i);
++count;
}
else if(cur[1]>next[0]){
intervals.erase(intervals.begin()+i+1);
++count;
}
else ++i;
}
return count;
}
};
这一次,我不选择删除,而选择直接跳过相应的区间,
因此时间复杂度为:排序需要O(nlgn),然后需要遍历一边需要O(n)
因此总的时间复杂度为O(nlgn)
class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
if(intervals.size()<2) return 0;
//sort with the most right of interval
sort(intervals.begin(),intervals.end(),[](const vector<int> &lhs,const vector<int> &rhs){
return lhs[1]<rhs[1];
});
int i=0;
int j=0;
int count=0;
while(j<intervals.size()-1)
{
auto cur=intervals[i];
auto next=intervals[j+1];
if(cur[1]==next[1]){
if(cur[0]<next[0]) ++j;
else {
i=j+1;
++j;
}
++count;
}
else if(cur[1]>next[0]){
++j;
++count;
}
else{
i=j+1;
++j;
}
}
return count;
}
};
上面的代码,我每一次都会判断两个区间右边的端点是否相等;从而增加了判断的时间;
我进一步的优化了一下;
class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
if(intervals.size()<2) return 0;
//sort with the most right of interval
sort(intervals.begin(),intervals.end(),[](const vector<int> &lhs,const vector<int> &rhs){
return lhs[1]<rhs[1];
});
int i=0;
int j=0;
int count=0;
while(j<intervals.size()-1)
{
auto cur=intervals[i];
auto next=intervals[j+1];
if(cur[1]>next[0]){
++count;
if(cur[1]==next[1]) i=j+1;
++j;
}
else{
i=j+1;
++j;
}
}
return count;
}
};