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

一道看起来不难的题目,却做了很久才AC。主要原因还是思路不清晰导致的。

思路一:直接求解,简单说就是蛮力算法O(N),依次遍历过去,判断是否合并插入。

我自己写了一个直接求解的代码,结果超时了。但是后面看答案,发现很多人都是用的蛮力,却没有超时。我想,可能是跟我用的erase跟insert有关系。

先上大神思路清晰的代码吧:

用新建的vector来存储答案,遇到与新间隔无交叠的就压入,遇到有交叠的就更新新间隔的范围。这样免去了erase和insert的麻烦。

最核心的,通过改变newInterval的范围来解决被覆盖的间隔!!

vector<Interval> insert(vector<Interval>& intervals, Interval newInterval) {
vector<Interval> ret;
auto it = intervals.begin();
for(; it!=intervals.end(); ++it){
if(newInterval.end < (*it).start) //all intervals after will not overlap with the newInterval
break;
else if(newInterval.start > (*it).end) //*it will not overlap with the newInterval
ret.push_back(*it);
else{ //update newInterval bacause *it overlap with the newInterval
newInterval.start = min(newInterval.start, (*it).start);
newInterval.end = max(newInterval.end, (*it).end);
}
}
// don't forget the rest of the intervals and the newInterval
ret.push_back(newInterval);
for(; it!=intervals.end(); ++it)
ret.push_back(*it);
return ret;
}

想了想,我那又长又臭的代码还是不放上来了...

思路二:二分搜索。我想,既然我自己写得O(n)的代码超时了,那只能想复杂度更少一些的代码了。于是就想用二分搜索来定位新间隔的起始和结束点应该在原间隔的哪个位置。

以上图为例,黑色的是初始间隔,脚标与间隔在vector中的关系是2n, 2n + 1。那么对于newInterval的start和end都有四种可能:

①比最小值还小,返回-1 -1

②比最大值还大,如图就是比16大,返回10 10

③落在某个范围里,如8, 返回  6 7。注意,边界值如1,2,3,5之类的,是算在范围里的。

④落在某个间隙里,如11, 返回 7 8

找到落在的范围后直接把覆盖的范围删除。在交叠的地方,我处理的还是很乱。

这份代码虽然AC了,但我自己并不满意。二分查找很混乱,交叠处理也很混乱,各种混乱!有时间再理一下吧。

注意: 判断奇数偶数时 ((r & 0x01) ==1) 里面的&一定要括起来!

vector<Interval> insert2(vector<Interval>& intervals, Interval newInterval)
{
if(intervals.empty())
{
intervals.push_back(newInterval);
return intervals;
}
Interval startPos = DividedSearch(intervals, newInterval.start);
Interval endPos = DividedSearch(intervals, newInterval.end);
if(endPos.end == -) //新间隔比所有的已有间隔都小 插到最前面
{
intervals.insert(intervals.begin(), newInterval);
}
else if(startPos.start == * intervals.size()) //新间隔比所有的已有间隔都大 插到最后面
{
intervals.push_back(newInterval);
}
else
{
if(startPos.start == endPos.start && startPos.start & 0x01 == ) //start与end都落在同一个间隙
{
intervals.insert(intervals.begin() + startPos.start / + , newInterval); //在该间隙插入
}
else if(startPos.start == endPos.start && (startPos.start & 0x01) == ) //start与end都落在同一个范围 什么都不做 原范围包含了新范围
{
}
else
{
//把覆盖的新范围幅值到被覆盖的第一个范围上
intervals[startPos.end / ].start = (newInterval.start < intervals[startPos.end / ].start) ? newInterval.start : intervals[startPos.end / ].start;
if(endPos.start == * intervals.size())
{
intervals[startPos.end / ].end = newInterval.end;
intervals.erase(intervals.begin() + startPos.end / + , intervals.end());
}
else
{
intervals[startPos.end / ].end = ((endPos.start & 0x01) == ) ? newInterval.end : intervals[endPos.start / ].end;
//擦除被覆盖的范围
intervals.erase(intervals.begin() + startPos.end / + , intervals.begin() + endPos.start / + );
}
} }
return intervals;
} //二分查找定位新间隔的最大值和最小值落在哪个范围 注意数字可能在两个范围的缝隙中
Interval DividedSearch(vector<Interval> intervals, int num)
{
if(num < intervals[].start) return Interval(-, -); //比最小值小
if(num > intervals.back().end) return Interval( * intervals.size(), * intervals.size()); //比最大值大 int l = , r = * intervals.size() - ;
Interval range(l, r);
while(l < r - )
{
int m = l + (r - l) / ;
int mnum = (m & 0x01 == ) ? intervals[m / ].end : intervals[m / ].start; //m是奇数对应end 是偶数对应start
int lnum = (l & 0x01 == ) ? intervals[l / ].end : intervals[l / ].start;
int rnum = (r & 0x01 == ) ? intervals[r / ].end : intervals[r / ].start;
if(lnum <= num && num <= mnum)
{
r = m;
}
else if(mnum <= num && num <= rnum)
{
l = m;
}
else
{
break;
}
}
int lnum = (l & 0x01 == ) ? intervals[l / ].end : intervals[l / ].start;
int rnum = (r & 0x01 == ) ? intervals[r / ].end : intervals[r / ].start;
if(num == lnum && ((l & 0x01) == ))
{
r = l; l = r - ;
}
else if(num == rnum && ((r & 0x0001) == )) //注意 (r & 0x0001) 一定要括起来
{
l = r; r = l + ;
}
return Interval(l, r);
}

还有,这道题的时间分布很奇怪,最快的居然是python。

【leetcode】Insert Interval(hard)★的更多相关文章

  1. 【题解】【区间】【二分查找】【Leetcode】Insert Interval & Merge Intervals

    Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessa ...

  2. 【leetcode】Insert Interval

    Insert Interval Given a set of non-overlapping intervals, insert a new interval into the intervals ( ...

  3. 【Leetcode】【Hard】Insert Interval

    Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessa ...

  4. 【LeetCode】986. Interval List Intersections 解题报告(C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 双指针 日期 题目地址:https://leetco ...

  5. 【leetcode】986. Interval List Intersections

    题目如下: Given two lists of closed intervals, each list of intervals is pairwise disjoint and in sorted ...

  6. 【leetcode】986. Interval List Intersections (双指针)

    You are given two lists of closed intervals, firstList and secondList, where firstList[i] = [starti, ...

  7. 【LeetCode】排序 sort(共20题)

    链接:https://leetcode.com/tag/sort/ [56]Merge Intervals (2019年1月26日,谷歌tag复习) 合并区间 Input: [[1,3],[2,6], ...

  8. 【LeetCode】380. Insert Delete GetRandom O(1) 解题报告(Python)

    [LeetCode]380. Insert Delete GetRandom O(1) 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxu ...

  9. 【LeetCode】436. Find Right Interval 解题报告(Python)

    [LeetCode]436. Find Right Interval 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博客: h ...

随机推荐

  1. MySQL配置文件my.cnf中文详解附mysql性能优化方法分享

    Mysql参数优化对于新手来讲,是比较难懂的东西,其实这个参数优化,是个很复杂的东西,对于不同的网站,及其在线量,访问量,帖子数量,网络情况,以及机器硬件配置都有关系,优化不可能一次性完成,需要不断的 ...

  2. 未能从程序集“System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”中加载类型“System.ServiceModel.Activation.HttpModule”。

    ********************************* 思路壹(也是网络上铺天盖地的通俗解决方案) 原因: 这是因为先安装了 .NET Framework , 随后启用了 .NET Fra ...

  3. dwz 在dialog里打开dialog

    需要在打开dialog里再弹出一个dialog的话,需要在打开第一个dialog的地方指定rel,这样就可以弹出第二个dialog而不是替换掉第一个dialog <a class="a ...

  4. Windbg学习使用

    WinDbg是微软发布的一款相当优秀的源码级(source-level)调试工具,可以用于Kernel模式调试和用户模式调试,还可以调试Dump文件. 1. WinDbg介绍:    Debuggin ...

  5. C语言的源程序字符集与执行字符集

    我们程序文件的字符集就是我们写出来的.c扩展名的文件的字符集,这里用的是系统默认的 ANSI 字符集,如下图: 上面的字符集我们不关心,我们关心的是 源程序的字符集 和程序的 执行字符集 ,源程序的字 ...

  6. css3常用标签

    30个最常用css选择器解析   你也许已经掌握了id.class.后台选择器这些基本的css选择器.但这远远不是css的全部.下面向大家系统的解析css中30个最常用的选择器,包括我们最头痛的浏览器 ...

  7. iOS 8 Xcode6 设置Launch Image 启动图片

    本人apem http://www.mamicode.com/info-detail-494411.html 如何设置App的启动图,也就是Launch Image? Step1 1.点击Image. ...

  8. 剑指Offer 替换空格

    题目描述 请实现一个函数,将一个字符串中的空格替换成“%20”.例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy.   思路: 替换空格,先遍历一遍记 ...

  9. opencv删除二值图中较小的噪点色块

    CvSeq* contour = NULL; double minarea = 100.0; double tmparea = 0.0; CFileDialog dlg(true); if (dlg. ...

  10. Android_bug之 task ':app:mergeDebugResources'. > Some file crunching failed, see logs f

    今天调试安卓程序遇到的问题Error:Execution failed for task ':app:mergeDebugResources'. > Some file crunching fa ...