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. 安卓自动化测试(2)Robotium环境搭建与新手入门教程

    Robotium环境搭建与新手入门教程 准备工具:Robotium资料下载 知识准备: java基础知识,如基本的数据结构.语法结构.类.继承等 对Android系统较为熟悉,了解四大组件,会编写简单 ...

  2. ecshop之transport和jquery冲突之完美解决方案

    众所周知:ecshop的transport.js文件和Jquery是冲突的,两个文件不能同时调用,现给出以下完美解决方案:原因分析:在transport.js文件中,大概 580行到590行之间,这个 ...

  3. js null和undefined

    在JavaScript开发中,被人问到:null与undefined到底有啥区别? 一时间不好回答,特别是undefined,因为这涉及到undefined的实现原理. 总所周知:null == un ...

  4. centos 安装mysql

    wget http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm rpm -ivh mysql-community-rele ...

  5. sass跨文件重写变量

    利用变量默认值: !default 你可以在变量尚未赋值前,通过在值的末尾处添加 !default 标记来为其指定. 也就是说,如果该变量已经被赋值, 就不会再次赋值, 但是,如果还没有被赋值,就会被 ...

  6. 常见HTTP错误代码大全

    一些常见的状态码为: 200 - 服务器成功返回网页404 - 请求的网页不存在503 - 服务不可用详细分解: 1xx(临时响应)表示临时响应并需要请求者继续执行操作的状态代码. 代码 说明100 ...

  7. 深入理解Java虚拟机之读书笔记三 内存分配策略

    一般的内存分配是指堆上的分配,但也可能经过JIT编译后被拆散为标量类型并间接地在栈上分配.对象主要分配在新生代的Eden区上,如果启动了本地线程分配缓冲,将按线程优先在TLAB上分配,少数情况下直接分 ...

  8. windowSoftInputMode属性讲解

    windowSoftInputMode属性讲解(下面这段内容我参考别人的博客,并加入我的一些意见) 我们从这个属性的名称中,可以很直观的看出它的作用,这个属性就是来设置窗口软键盘的交互模式的.andr ...

  9. iOS 不规则的ImageView

    http://blog.csdn.net/kevinpake/article/details/41205715 我们在做iOS开发的时候,往往需要实现不规则形状的头像,如: 那如何去实现? 通常图片都 ...

  10. cocos2d界面渲染

    渲染是visit函数来做的, visit是先将不可见的节点和他所有的子节点都跳过, 然后再看节点的子节点是否为空, 如果为空的话直接看这个节点是否在摄像机可见范围之内, 如果在就渲染这个节点, 否则什 ...