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. NOIP2005 等价表达式

    题目描述 明明进了中学之后,学到了代数表达式.有一天,他碰到一个很麻烦的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数 ...

  2. hdu.1111.Secret Code(dfs + 秦九韶算法)

    Secret Code Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Tota ...

  3. Ubuntu 12 修改当前用户密码:new password is too simple

    修改当前登录用户的密码,通常使用如下命令: $ passwd Old password:****** New password:******* Re-enter new password:****** ...

  4. OS X Framework Library not loaded: 'Image not found'的解决办法

    参考:OS X Framework Library not loaded: 'Image not found' 1.首先将相应的framework手动复制到/System/Library/Framew ...

  5. MAS 移动业务整合系统

    AppCan MAS是基于高性能NODEJS架构开发的企业移动后端整合系统,内置各种标准协议组件,统一移动业务前后端标准开发技术:同时通过基于策略配置的数据缓存机制,聚合业务数据并发连接不同的后端业务 ...

  6. 深入理解Java虚拟机之读书笔记二 垃圾收集器

    1.对象已死? a.引用计数算法:缺点是它很难解决对象之间的相互循环引用的问题,Java语言中没有选用它. b.根搜索算法(GC Roots Tracing):通过一系列的名为"GC Roo ...

  7. BZOJ1588——[HNOI2002]营业额统计

    1.题目大意:一个简单的treap模板题(我才不告诉你题目少一句话呢,看discuss去 2.分析:treap模板题 #include <cstdio> #include <cstd ...

  8. Retina视网膜屏中CSS3边框图片像素虚边的问题

    虽然CSS3新增了这个功能,但是在W3school里面并没有给出具体详细的解释,还好网上不乏大神给你我们很全面的解释其中的原理-css3:border-image边框图像详解 边框图片的原理是四个角不 ...

  9. PHP中九大缓存技术总结

    PHP缓存包括PHP编译缓存和PHP数据缓存两种.PHP是一种解释型语言,属于边编译边运行的那种.这种运行模式的优点是程序修改很方便,但是运行效率却很低下.PHP编译缓存针对这种情况做改进处理,使得P ...

  10. Android 趣味应用—— 短信编辑器

    修改短信数据库,从而生成任意手机号发送的短信. AndroidManifest.xml <?xml version="1.0" encoding="utf-8&qu ...