区间问题刷题系列

读完本文,题解几类区间问题。

本文Leetcode题解:

56 合并区间 (Medium)

1288 删除被覆盖的区间 (Medium)

986 区间列表的交集 (Medium)

57 插入区间(Hard)

做区间问题最重要的两点:排序画图

排序,当然很重要。如果区间的列表是任意散落的,不方便我们统一区间之间的关系,遍历的时候也会带来些许麻烦。试想一下,区间起始一会从1跳到8,又回到4,我们就没法很好处理他们之间的关系。因此我们通常按照起始起点从小到大排序。

画图其实是为了帮助你找到区间与区间的关系。例如重叠时候有几种位置可能性,不重叠又有几种?因此画图找关系。

不多说了,做题。

56 合并区间

在这里插入图片描述

也就是说我们需要遍历区间,将重叠的区间合并成新的区间。

由于起点是按照从小到大排序的,我们需要将当前区间的的开头与res内容当中最后的尾部对比。
大家可以动手画画图。
如果当前区间的开头与上一个(res尾部)区间产生了重叠,那么就更新res尾部。
如果没有产生重叠,那就直接让这个区间添加到res当中,继续下一次遍历。

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        if(intervals.size()==0) return {};
        //放答案
        vector<vector<int>> res;
    
        //排序
        sort(intervals.begin(),intervals.end());
        res.push_back(intervals[0]);

       for(int i = 1;i<intervals.size();i++){
            //重叠
          if(!(intervals[i][0]>res.back()[1])){
                 res.back()[1] = max(intervals[i][1],res.back()[1]);
            }
            else res.push_back(intervals[i]); //不重叠
        }

       return res;
    }
};

1288 删除被覆盖的区间 (Medium)

有了上一题的基础,做这道题就简单了。但是需要注意,当两个区间起始相同时,我们将会出现这种情况。
在这里插入图片描述
很显然当开头相同时,应该按照末尾降序的情况排。否则出现右边的情况是,无法将上面的区间有效删除。

class Solution {
public:
    int removeCoveredIntervals(vector<vector<int>>& intervals) {
       if(intervals.size()==0) return {};
       vector<vector<int>> res;
       sort(intervals.begin(),intervals.end(),cmp);
       res.push_back(intervals[0]);
       for(int i=1;i<intervals.size();i++){
         if(!(intervals[i][0]>=res.back()[0]&& intervals[i][1]<=res.back()[1]))  res.push_back(intervals[i]);
       }
       return res.size();
    }

    static bool cmp(const vector<int> &a,const vector<int> &b){
        if(a[0]==b[0]) return b[1]<a[1];
        else return a[0]<b[0];
    }
};

986 区间列表的交集 (Medium)

在这里插入图片描述
这道题的改变在于,有两个区间列表来找出他们的重叠部分。

比较需要注意的是,
我B列表中的某个区间可能同时与A区间好几个的区间都产生重叠,因此需要使用两个指针,来控制比较的进度。

class Solution {
public:
    vector<vector<int>> intervalIntersection(vector<vector<int>>& A, vector<vector<int>>& B) {
     int i=0,j=0;
     vector<vector<int>> res;
     while(i<A.size()&&j<B.size()){
        //相交
        if(!(A[i][1]<B[j][0]  || A[i][0]>B[j][1])){
          vector<int> tmp;
          tmp.push_back(max(A[i][0],B[j][0]));
          tmp.push_back(min(A[i][1],B[j][1]));
          res.push_back(tmp);  
        }
        //指针控制状态
         if(B[j][1]<A[i][1]) j++;
         else i++;
     }
     return res;
    }
};

57 插入区间(Hard)

在这里插入图片描述
对于这个newInterval,将其初始化为我们要比较的标准,使用leftright来说明因为冲突而重构后的范围。遍历区间列表,如果找到与其冲突的区间(可能有好几个都符合冲突情形的区间)就要进行更新操作,当这种冲突状态结束后(想想我们应该怎么在代码中描述?),将最终的更新区间结果插入到结果中。

如果当前遍历的区间不存在什么与比对区间冲突的情况,那就直接天即进去答案。

其实也不算太麻烦,关键在于想清楚这个处理的过程。 我一开始犯的错误在于,找出重叠区域(做标记),更新成新区间。最后在全局遍历的时候再重新填入,其实这样处理很麻烦,也容易出错。

所以这道题解很关键的是,重新生成的新区间应该在什么时候加进去?

我们刚刚讲到了left和right,仔细想想。
1)如果newInterval能够不与列表中的区间产生冲突,即可以直接插入,那么left和right的范围自然是初始的newInterval值。

int left=newInterval[0],right = newInterval[1];

2)如果newInterval在区间内产生了冲突,我们将会在区间冲突结束的地方开始插入新结果。

但是我们还得注意一个细节,如果newInterval直接大于所有列表区间,不能在循环中得到结果。因此我们应该用一个flag来表示,如果flag在区间中改变,表示该newInterval插入在区间内便完成。当flag没有变化,说明循环中没有插入newInterval的动作,直接添加在答案末尾即可。

看代码配合讲解更好体会。

class Solution {
public:
    vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
     vector<vector<int>> res; 
     if(intervals.size()==0) {
         res.push_back(newInterval);
         return res;
     }
     bool bflag = true;
     int left=newInterval[0],right = newInterval[1];
     for(int i=0;i<intervals.size();i++){
      if(!(intervals[i][1]<left||intervals[i][0]>right)){  //与新区间冲突
        left = min(left,intervals[i][0]);
        right = max(right,intervals[i][1]);
        }
      else {
      //关键:区间内newInterval(可能没有变化,也可能是和冲突区间合并的新结果)的插入
        if(intervals[i][0]>right && bflag){  
            res.push_back({left,right});
            bflag = false; 
        }  
        res.push_back(intervals[i]);
      }
     }
     if(bflag) res.push_back({left,right}); //直接加在结尾
     return res;
     }  
};

整体思路:
遍历原数组,如果当前区间和新区间没有交集,则直接存入答案;
如果有交集,便和新区间合并,更新新区间的左右边界;
如果当前区间和新区间无交集且大于新区间,则新区间和后面所有的区间都可存入答案。

作者:wo-shi-ge-hun-zi
链接:https://leetcode-cn.com/problems/insert-interval/solution/cyi-ci-bian-li-zhi-jie-fa-jiao-hao-li-jie-by-wo-sh/

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值