leetcode--------无重叠区间

题目:

给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠

注意:

  1. 可以认为区间的终点总是大于它的起点。
  2. 区间 [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;
    }
};

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值