57. 插入区间(中等)

Blind 75 › 57. 插入区间(中等) (第 1 章)
文章工具

题目

给你一个已经按左端点升序排好、且两两不重叠的区间列表,例如 [[2,4],[6,8]];再给一个新区间 [5,7]。把新区间插进去,如果它与原区间有交点,就把它们合并成一个区间;插完后仍需保持左端点升序、且两两不重叠。

两个区间只要至少共享一个点,就认为重叠——包括只共享端点。例如 [1,4] 和 [4,6] 重叠,应合并成 [1,6]。

自造示例:[[2,4],[6,8]] 插入 [3,7] → [[2,8]];再如 [[1,2],[6,9]] 插入 [3,5] → [[1,2],[3,5],[6,9]]。

约束:区间个数 0 ~ 104;每个区间含两个整数,0 ≤ start ≤ end ≤ 105;原列表已按左端点升序且无重叠;新区间长度同样为 2。不要求原地修改,可新建数组返回。

思路

一句话:因为原列表已经有序,每个原区间相对新区间只可能落在三种位置之一——左边、重叠、右边;一次线性扫描分三段处理即可。

先想最直白的做法:把新区间塞进原列表,再按左端点排序,然后从头到尾合并重叠区间。这个思路完全正确,但浪费了题目给的“已经按左端点排好序”这个条件,多花一次 O(n log n) 的排序。

关键观察:原区间按左端点递增,所以相对新区间而言,会出现一个连续前缀“完全在左”、一个连续中段“可能与新区间重叠”、一个连续后缀“完全在右”。我们只需要:

  • 左边:原区间右端点 < 新区间左端点,不可能碰,直接保留;
  • 重叠:原区间左端点 ≤ 新区间右端点,合并并不断扩展新区间;
  • 右边:从某个位置开始全部在原新区间之后,直接照抄。

重叠区间的“合并”就是不断取左右边界的最小值和最大值。因为一旦进入重叠段,后续的区间也可能连着叠,所以要把中段一次吃完再放入答案。

解法

用指针 i 从左往右扫一遍,ans 存结果:

  1. 先把“完全在新区间左边”的区间加入答案。
  2. 再处理所有“与新区间重叠”的区间,持续更新合并后的 [start, end]。
  3. 把合并后的新区间加入答案。
  4. 最后把“完全在新区间右边”的区间全部加入答案。

以 [[2,4],[6,8],[10,12]] 插入 [5,11] 为例:

当前原区间与新区间关系操作答案
[2,4]4 < 5,完全在左直接保留[[2,4]]
[6,8]6 ≤ 11,重叠合并成 [5,11][[2,4]]
[10,12]10 ≤ 11,仍重叠合并成 [5,12][[2,4]]
—扫描结束放入 [5,12][[2,4],[5,12]]

下图把上面 4 个步骤串成流程,并逐步演示:

57. 插入区间(中等) 解法步骤流程图
图① 解法步骤流程图(共 4 步)。
57. 插入区间(中等) 按步骤逐步执行的动画
动图② 按步骤依次推进(循环播放)。

C++

C++ 片段需补全 main() 函数才能运行

🔒

本篇为付费内容

您已阅读试读部分,购买后即可解锁全文。

⚠️ 本站内容已做唯一性标记并受版权保护,未经授权禁止转载,侵权必究。