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. [百度地图] ZMap 与 MultiZMap 封装类说明;

    ZMap.js 与 MultiZMap 说明 1. ZMap 与 MultiZMap 都是封装一些地图常用的使用方法,类方法功能大多使用 prototype 原型 实现: ZMap 在一个页面只能使用 ...

  2. GATK软件介绍

    背景介绍 GATK全称是The Genome Analysis Toolkit,是Broad Institute(The Broad Institute, formerly the Broad Ins ...

  3. Codeforces Round #270 1001

    Codeforces Round #270 1001 A. Design Tutorial: Learn from Math time limit per test 1 second memory l ...

  4. 使一个div始终显示在页面中间

    使一个div始终显示在页面中间 假设我们有一个div层:<div id=”myDiv”></div> 首先,我们用css来控制它在水平上始终居中,那么我们的css代码应该是这样 ...

  5. 天翼宽带政企网关B2-1P 如何获得超级管理员账号?

    RT 用useradmin没办法做NAT,想进telecomadmin里面看看,,,,,并且已经使用过nE7jA%5m这个密码登录,没有用! 求办法!!! 最佳答案 查找超级管理员密码方法: 1.用光 ...

  6. 【PHP面向对象(OOP)编程入门教程】15.static和const关键字的使用(self::)

    static关键字是在类中描述成员属性和成员方法是静态的:静态的成员好处在哪里呢?前面我们声明了“Person”的人类,在“Person”这个类里如果我们加上一个“人所属国家”的属性,这样用“Pers ...

  7. 【PHP面向对象(OOP)编程入门教程】19.抽象方法和抽象类(abstract)

    在OOP语言中,一个类可以有一个或多个子类,而每个类都有至少一个公有方法做为外部代码访问其的接口.而抽象方法就是为了方便继承而引入的,我们先来看一下抽象类和抽象方法的定义再说明它的用途. 什么是抽象方 ...

  8. ThinkPHP框架表单验证

    对注册到test表的表单进行验证 在注册之前要对表单进行验证: 用户名非空验证,两次输入密码必须一致即相等验证,年龄在18~50之间即范围验证,邮箱格式正则验证. 自动验证是ThinkPHP模型层提供 ...

  9. linux 学习之路

    很多同学接触Linux不多,对Linux平台的开发更是一无所知. 而现在的趋势越来越表明,作为一个优秀的软件开发人员,或计算机IT行业从业人员, 掌握Linux是一种很重要的谋生资源与手段. 下来我将 ...

  10. HDU 4803 Poor Warehouse Keeper

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4803 解题报告:有一个记录器,一共有两个按钮,还有两行屏幕显示,第一行的屏幕显示的是数目,第二行的屏幕 ...