57. Insert Interval

原题链接

Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary). You may assume that the intervals were initially sorted according to their start times.

例如,原来的区间集是[1,2],[3,5],[6,7],[8,10],[12,16],插入的新区间是[4,9],合并后就变成了[1,2],[3,10],[12,16]。解决问题的关键是找到与新区间有重合的区间。一种方法是,找到一个重合的区间后,马上与插入区间合并,然后再看与后面的区间是否重合。例如,按上面的例子,首先找到[3,5]与[4,9]重合,合并成[3,9];然后[3,9]与[6,7]比较,合并后仍是[3,9];[3,9]继续与[8,10]比较,如此前进。这种方法的合并操作次数较多,效率低,写起来也比较麻烦。

实际上由于区间集是有序的,被合并的区间一定是连续的,不可能出现[1,2],[6,7]被合并而[3,5]没被合并的情况。所以我们可以去找合并区间段的起始区间和结束区间。按顺序遍历,第一个找到的end比插入区间的start大的区间,即为起始区间,在它前面的区间都是与插入区间没有重合的,不用作改动。但起始区间也不一定与插入区间重合,要继续看后面的判断。接着遍历,第一个找到的end比插入区间end大的区间为结束区间,在它后面的区间都不可能和插入区间重合了。

找到起始和结束区间后,下一步就要确定合并后区间的start和end了,start应为起始区间和插入区间的start中较小的一个;end的话要比较结束区间的start和插入区间end的大小,如果前者大,说明结束区间与插入区间也是不重合的,合并区间的end等于插入区间end,如果后者大,则合并区间的end等于结束区间的end。

/**
 * Definition for an interval.
 * struct Interval {
 *     int start;
 *     int end;
 *     Interval() : start(0), end(0) {}
 *     Interval(int s, int e) : start(s), end(e) {}
 * };
 */
class Solution {
public:
    vector<Interval> insert(vector<Interval>& intervals, Interval newInterval) {
        vector<Interval> v;
        int i;
        
        for(i=0; i<intervals.size(); i++) {
            if(newInterval.start<=intervals[i].end) {
                if(newInterval.start>intervals[i].start) {
                    newInterval.start = intervals[i].start;
                }
                break;
            }
            else v.push_back(intervals[i]);//添加在起始区间前的区间
        }

        for(; i<intervals.size(); i++) {
            if(newInterval.end<intervals[i].end) {
                if(newInterval.end>=intervals[i].start) {
                    newInterval.end = intervals[i].end;
                    i++;// 结束区间与插入区间重合
                }
                break;
            }
        }
        v.push_back(newInterval);
        for(; i<intervals.size(); i++) {
            v.push_back(intervals[i]);// 添加在结束区间后的区间
        }
        return v;
    }
};

代码中我没有新建一个合并区间变量,而是直接修改了newInterval的start和end,并把修改后的newInterval当做合并区间,这样并不影响算法的运行,还能节省一个变量开销。对于返回的结果,如果在原来的vector上直接修改,需要移走一些元素,并在特定位置上插入合并区间,vector的insert/erase方法复杂度与插入/删除位置后的元素个数线性相关,相比之下push_back的复杂度仅为常数时间,所以我选择了新建vector并向其中添加元素。整个算法的时间复杂度为O(n)。

改进方法可以用二分查找来确定起始结束区间,时间复杂度降为O(lgn)。但最后构造新区间集时,仍要遍历整个旧区间集(除了起始结束区间之间的区间),所以整个算法理论上的时间复杂度仍为O(n)。

转载于:https://my.oschina.net/cofama/blog/884291

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值