您的位置:首页 > 其它

LeetCode 57. Insert Interval 题解

2017-10-23 09:07 429 查看

LeetCode 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]
.

题目分析

这道题大意先给定一个有序区间数组, 再向这个数组里面插入一个区间使其仍然有序, 并对插入后的数组进行区间合并操作,然后返回。

嗯。这题我还真不知道为什么是Hard,23333……真的水呀。本来想先试一种暴力解法为一种感觉更优一点的解法做铺垫的,结果发现直接交了成绩还不错,就懒得写更好一点的了2333… -.- 不过思路等下还是会大致讲一下的。

其实这道题…..怎么说呢。可以先确定一个复杂度下界吧。O(m)的下界复杂度, 其中m是返回的合并后的数组长度。毕竟无论怎样你都得构建一个这样的数组 对吧。。。

为啥说这个呢。。。主要是这题水没啥思路好写的。就扯点其他的吧。这个下界知道了还是有一定指导意义的, 会让你之后放弃做一些意义不是很大的优化。。。

嗯不水了。进入正题。这题一个直接的想法就是扫描一遍区间数组, 能插就插入, 该合并就合并啊。。。

话是这样说,如何做呢?

下面就说几点重要的地方吧。 其实画个区间图就能很轻松看出来。

1.
newInterval.start > intervals[i].end
时, 表示还没有到插入的区间。此时直接加入
ans
就可以了。

2. 处理完上面那个之后的首个
intervals[i]
是需要分情况讨论的。先说简单的情况:
newInterval.end < intervals[i].start
的时候。证明这个插入的区间不需要合并。(画图显然的)

3. 复杂一点的情况在这里: 如果不满足上面那个条件呢? 那就说明至少有一个区间要和新插入的区间进行合并。而且这些需要合并的区间是连续的(注意这一点, 优化的时候会再用到)

那么朴素的想法就是, 先取
intervals[i]
newInterval
合并,再考察是否满足上面 2 中那个条件, 如果不满足, 继续合并下一个。知道满足为止(满足的话即下一个Interval不会和合并的Interval产生交集)

4. 之后将剩下的直接添加到
ans
区间数组里。(合并完成后, 右边的那些不需合并的区间不变)

复杂度分析:

这个算法复杂度主要在于扫描一遍初始数组, 故复杂度易得为O(n),其中 n 为初始数组长度。

划重点: 最坏情况下 m,n同阶, m=n+1, 所以结合刚才推导出的时间复杂度下限, 这算法还算不错:)

(不过这种题为什么是Hard…)

稍微优一点点的解

看到这题其实立马想到的就是二分, 毕竟有序…二分之后为什么可以优化呢? 那就得看前面那个算法复杂在了哪儿了。步骤
1, 4
是必不可少的。那就只能在
3
上面做文章了。 注意到合并的区间连续, 也就是只要确定头尾即可。而二分就是做这样一件事情:确定新插入区间影响原数组的头部和尾部。这样就可以不用执行多次, 而可以一次就合并完了。

这个算法的复杂度是多少呢? 我直接给出下面的公式:

O(max(m,logn))

比较菜, 不确定准确的是不是这样, 但是大致是这样应该没有问题。这个复杂度说明了什么呢? 两个事情:

1. 较好的情况下, 能到达复杂度下界。

2. 较坏的情况, 复杂度和上面第一种方法一样。

还有这样做编程实现有点麻烦。。。所以看到法一的performance还不错就懒了 ~。~

下面是方法一的具体代码实现:

class Solution {
public:
Interval merge(Interval &a, Interval &b) {
return Interval(min(a.start, b.start), max(a.end, b.end));
}
vector<Interval> insert(vector<Interval>& intervals, Interval newInterval) {
vector<Interval> ans;
int i = 0;
while (i < intervals.size() && intervals[i].end < newInterval.start) {
ans.push_back(intervals[i]);
i++;
}
if (i < intervals.size() && newInterval.end < intervals[i].start) ans.push_back(newInterval);
else {
auto t = newInterval;
while(i < intervals.size() && intervals[i].start <= t.end) {
t = merge(t, intervals[i]);
i++;
}
ans.push_back(t);
}
while (i < intervals.size()) {
ans.push_back(intervals[i]);
++i;
}
return ans;
}
};


其他细节

emmmm…这题唯一要注意的就是多过程处理时,每个过程交界处的处理要做到不重不漏, 特别小心。 这题我是分了三个过程来处理。

~。~ 这真是Hard中最水的一题了。 没有之一。 憋不出什么话说了。 既然我不知道说什么, 那我也就不知道在这里写些什么了。就这样吧。

The End.

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode