leetcode_57.插入区间

给出一个无重叠的 ,按照区间起始端点排序的区间列表。

在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。

示例 1:

输入: intervals = [[1,3],[6,9]], newInterval = [2,5]
输出: [[1,5],[6,9]]

示例 2:

输入: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
输出: [[1,2],[3,10],[12,16]]
解释: 这是因为新的区间 [4,8] 与 [3,5],[6,7],[8,10] 重叠。

解析:本题是基于上一题的修改版,因此提供两种解决方法,第一种是在上一题的基础上修改,第二种是不基于上一题的新思路。

第一种,在上一题的基础上修改。上一题提供的起始集合便是未排序,包含重叠区间的给定容器。而本题是要求将给定区间插入原集合中。最简单的办法便是将区间直接加入原集合,然后交付由上一题的函数计算便可。
如何减少时间,上一题的许多时间消耗在了给集合排序上,我们可以利用原集合有序的特点,使用二分法手动插入新区间。

class Solution {
public:
    vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
        int l = 0;
        int r = intervals.size();
        int m;
        while(l<r){
            m = l + (r-l)/2;
            if(intervals[m][0]<newInterval[0]) l=m+1;
            else if(intervals[m][0]>newInterval[0]) r=m;
            else{
                if(intervals[m][1]<newInterval[1]) l=m+1;
                else if(intervals[m][1]>newInterval[1]) r=m;
                else return intervals;
            }
        }
        intervals.insert(intervals.begin()+l,newInterval);
        //以下是上一题的部分
        int n = intervals.size();
        vector<int> starts, ends;
        for (int i = 0; i < n; ++i) {
            starts.push_back(intervals[i][0]);
            ends.push_back(intervals[i][1]);
        }
        vector<vector<int>> res;
        sort(ends.begin(),ends.end());
        for (int i = 0, j = 0; i < n; ++i) {
            if (i == n - 1 || starts[i + 1] > ends[i]) {
                res.push_back({starts[j], ends[i]});
                j = i + 1;
            }
        } 
        return res;
    }
};

第二种方法,即忽略上一题的结果,重新编程。
很容易将原区间分成三部分,一是完全小于新区间的区间,二是与新区间有重叠部分的区间,三是完全大于新区间的区间。对于一和三两部分,我们可以不予理会,直接将其准备输出。那么我们只需要将第二部分的区间进行合并即可。
定义索引n,遍历整个集合,对于第一部分和第三部分,将其插入待输出结果。
对于第二部分的区间,利用其数值更新新区间的数组,最后将新区间插入待输出结果。
整个过程不再需要排序,也不需要新的额外空间,时间复杂度O(N),空间复杂度O(1)

class Solution {
public:
    vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
        vector<vector<int>> res;
        if(intervals.size()==0) return res.push_back(newInterval),res;
        int n = 0;
        //所有小于新区间的区间
        while(n<intervals.size()){
            //如果结束点小于新区间起始点
            if(intervals[n][1]<newInterval[0]){
                res.push_back(intervals[n++]);
            }
            else break;
        }
        //计算并插入合并后的区间
        while(n<intervals.size()){
            //如果起始点小于等于新区间结束点,即需要合并
            if(newInterval[1]>=intervals[n][0]){
                //如果起始点小于新区间起始点
                if(intervals[n][0]<newInterval[0]){
                    newInterval[0]=intervals[n][0];
                }
                //如果结束点大于新区间结束点
                if(intervals[n][1]>newInterval[1]){
                    newInterval[1]=intervals[n][1];
                }
                ++n;
            }
            else break;
        }
        res.push_back(newInterval);
        //剩下的区间
        while(n<intervals.size()){
            res.push_back(intervals[n++]);
        }
        return res;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值