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. .net利用NPOI导入导出Excel

    NPOI在.net中的操作Excel 1.读取 using (FileStream stream = new FileStream(@"c:\客户资料.xls", FileMode ...

  2. IOS开发之----NSDictionary,JSON和XML互相转换

    本文永久地址为 http://www.cnblogs.com/ChenYilong/p/4044521.html,转载请注明出处.     -(void)test {     //XML文本范例   ...

  3. 控制器View的生命周期及相关函数是什么?你在开发中是如何用的?

    * 1.首先判断控制器是否有视图,如果没有就调用loadView方法创建:通过storyboard或者代码: * 2.随后调用viewDidLoad,可以进行下一步的初始化操作:只会被调用一次: * ...

  4. CentOS的SSH,Putty配置说明

    基本资源: CentOS5.5 (32位) , Mysql6.0 ,Putty ,SSH   Step: 1.VMWare中装好CentOS    A. 可能存在ifconfig等命令无法正常识别) ...

  5. MSP430G2333下位机乘法运算需要注意的一个问题

    背景: 最近负责为主板管理电源的电源管理模块编写软体,使用的MCU为MSP430G2333.功能上很简单,即通过板子上的硬件拨码设定,或者通过IIC与主板通信,由主板的BIOS决定开机及关机的延时供电 ...

  6. cf#306D. Regular Bridge(图论,构图)

    D. Regular Bridge time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...

  7. VS2013 Community配置OpenCV3.0.0

    配置环境:32位win7系统+VS2013 Community版本 1.首先从OpenCV官网上下载最新版本的OpenCV for Windows. 2.直接双击打开下载得到的opencv-3.0.0 ...

  8. Error 0x800704cf

    重装了系统,改过网络配置,结果共享和打印机连不上,显示Error 0x800704cf 在本地连接的属性里将"Client for Microsoft Networks"勾选上就可 ...

  9. 如何使用java自定义注解?demo

    1.Description.java package kzfy.bk.com; import java.lang.annotation.Documented; import java.lang.ann ...

  10. BZOJ1500——维修序列

    动态的最大子段和 就是splay啊,说一下GSS1吧,维护四个值,一个是这个区间和(下面说sum), 一个是从左边开始的最大和(下面说ls)和右边开始的最大和(下面说rs), 还有一个就是最大区间和( ...