LeetCode-Insert Interval

算法分析与设计,第10周博客

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.

Example 1:
Given intervals [1,3],[6,9], insert and merge [2,5] in as [1,5],[6,9].

Example 2:
Given [1,2],[3,5],[6,7],[8,10],[12,16], insert and merge [4,9] in as [1,2],[3,10],[12,16].

This is because the new interval [4,9] overlaps with [3,5],[6,7],[8,10].

给定一组相互之间没有叠加并根据开始值按升序排好的区间集合,给出一个新的区间,把这个新的区间加到这个数组中,

把它放到合适位置,并且如果需要的话,把有叠加的区间合并。

先来看区间的定义,很简单,两个整数,分别指出区间的开始值和结束值:

/**
 * Definition for an interval.
 * struct Interval {
 *     int start;
 *     int end;
 *     Interval() : start(0), end(0) {}
 *     Interval(int s, int e) : start(s), end(e) {}
 * };
 */
那么,再来看下怎么样的两个区间需要合并,设有两个区间a和b,并且a.start <= b.start:

那么,当 b.start <= a.end时,两个区间需要合并,并且合并后的区间c有

c.start = a.start,c.end = max(a.end, b.end);

这样,就把基本的概念都搞清楚了。

那么,面对这个问题的解决办法呢?

首先,对整个数组进行分组,整个数组可以分成三个部分:

  1. 位于插入区间之前的部分。这个部分的区间可以原封不动的加入结果中。
  2. 与插入区间有交集的部分。这个部分需要整合成一个新的区间,然后加入到结果中。
  3. 位于插入区间之后的部分。这个部分的区间也可以原封不动的加入到结果中。
那么,我们需要做的事就很清楚了,找出和插入区间有交集的部分。而整个数组又是按照开始值排好序的,那么就可以使用二分法来查找到插入区间和哪些区间有交集。
设插入区间p和数组中第i个至第j个区间有交集,那么有:
  1. p.start >= i.start && p.start <= i.end
  2. p.end >= j.start && p.end <= j.end
那么这样合并后的区间mid有,mid.start = i.start , mid.end = j.end;

那么,只要用p.start 和p.end 分别作为搜索值,使用二分查找法,找出的下标就分别是 i 和 j 。这样,这个问题就得到解决了。

二分查找的函数如下,这个函数返回的是intervals中start值第一个小于target值的interval,但是它不保证其end会大于target:

    int search(vector<Interval>& intervals, int low, int high, int target) {
        while (low < high) {
            int mid = low+((high-low+1)>>1);
            if (intervals[mid].start == target) {
                return mid;
            } else if (intervals[mid].start > target) {
                high = mid-1;
            } else {
                if (mid == low)
                    return low;
                low = mid;
            }
        }
        return low;
    }
因为上面函数的稍微的特殊性,所以需要注意,返回的值所代表的区间是否和插入区间有交集。如果没有交集,那么需要把这个区间也单独加入到结果中。

    vector<Interval> insert(vector<Interval>& intervals, Interval newInterval) {
        vector<Interval> res;
        if (intervals.size() == 0) {
            res.push_back(newInterval);
            return res;
        }
        int start = search(intervals, 0, intervals.size()-1, newInterval.start);
        int end = search(intervals, 0, intervals.size()-1, newInterval.end);
        res.insert(res.end(), intervals.begin(), intervals.begin()+start);
        Interval mid;
        mid.start = intervals[start].start < newInterval.start ? intervals[start].start : newInterval.start;
        if (intervals[start].end < newInterval.start) {
            res.push_back(intervals[start]);
            mid.start = newInterval.start;
        }
        mid.end = intervals[end].end >= newInterval.end ? intervals[end].end : newInterval.end;
        res.push_back(mid);
        if (intervals[end].start > newInterval.end) {
            res.back().end = newInterval.end;
            res.push_back(intervals[end]);
        }
        res.insert(res.end(), intervals.begin()+end+1, intervals.end());
        return res;
    }

下面来看下这个函数的时间复杂度,首先有用两次二分查找法,时间复杂度是O(log(n)),然后需要把原来数组中的区间加到结果中去,时间复杂度是O(n),所以总体的时间复杂度也还是O(n)。这也是无法避免的,因为需要把原数组的元素添加到新的数组中去,我们利用了二分查找法来减轻了一些时间复杂度,把从i到j的时间复杂度从O(j-i)变成了O(log(n)),所以当插入区间的跨度越大时,这个方法的效率就越高。




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值