30 秒识别Q1 · 986 Interval List Intersections:给两个各自有序且内部不相交的区间列表,求它们的交集。你的第一反应是哪个模式?
看答案
区间 + 双指针。两个列表都已排序,交集是 [max(起点), min(终点)],非空就收下,然后终点小的那一方前进。「两个有序列表」这个形状同时也是第 02 章的信号,但处理对象是区间,模板在本章。
按起点排序,用来合并、插入、判重叠(模板 A);按终点排序,用来「最多能留下几个互不重叠的」(模板 B 之外的那类贪心)。选错排序键,题就做不出来——这是本章唯一需要判断的地方。
「同时进行的最大数量」(会议室 II)是另一种形态:把起点和终点拆开各自排序,沿时间轴推进,开始 +1、结束 −1,峰值就是答案。这套写法叫扫描线,换成小顶堆存「最早结束时间」也是同一件事。
| 题面出现… | 想到 |
|---|---|
| 「合并重叠区间」 | 按起点排序 + 合并(模板 A) |
| 「插入一个新区间并合并」 | 同上;不排序的三段式写法更快(57) |
| 「最少删掉几个使其互不重叠」 | 按终点排序贪心,留结束最早的 |
| 「需要几间会议室 / 最多同时有几个」 | 扫描线或小顶堆(模板 B) |
| 「用最少的箭射爆所有气球」「区间覆盖」 | 按终点排序贪心,和 435 同源 |
输入是一堆 [start, end] | 先问自己:按起点排还是按终点排 |
按终点排序那一类(435、452)本质上是贪心(第 15 章),只是贪心对象恰好是区间;把它们放在本章是因为识别信号来自「区间」这个形状。「区间和」是完全不同的题——那是前缀和(第 13 章),和排序无关。需要反复动态查询区间最值 / 区间修改的,属于线段树,本书明确不覆盖。
■ 【骨架】 不变,闭着眼默写 ■ 【插槽】 随题变化,写题前先问自己填什么
def merge_intervals(intervals):
intervals.sort() # 【骨架】按起点排序 —— 区间题的第一行
out = []
for s, e in intervals: # 【骨架】
if out and s <= out[-1][1]: # 【插槽】重叠判定:<= 表示"碰到端点也算重叠"
out[-1][1] = max(out[-1][1], e) # 【插槽】重叠了怎么办:合并 / 计数 / 丢一个
else:
out.append([s, e]) # 【骨架】不重叠就新开一段
return out
s <= out[-1][1] 里的等号要不要,取决于题目认不认「端点相碰算重叠」——56 认,435 不认,见翻车点②。def min_meeting_rooms(intervals):
starts = sorted(x[0] for x in intervals) # 【骨架】起点和终点拆开各自排序
ends = sorted(x[1] for x in intervals)
rooms = best = j = 0
for s in starts: # 【骨架】按时间推进,每来一个开始
while j < len(ends) and ends[j] <= s: # 【插槽】<= 表示"上一场刚结束就能接下一场"
j += 1 # 【骨架】先把已结束的房间腾出来
rooms -= 1
rooms += 1 # 【骨架】占一间
best = max(best, rooms) # 【插槽】答案:峰值 / 每一刻的值
return best
[[1,100],[2,3],[3,4]] 会留下那个超长区间,答案偏小。[1,4] 和 [4,5] 重叠(要合并),435 认为它们不重叠(都能留下)。同一个 <= / < 的差别,读题时必须先确定。intervals.pop() 会打乱迭代。一律往新列表 out 里追加,只改 out[-1][1]。[[1,2],[2,3]] 这种首尾相接的输入会算成 2 间——房间数确实短暂到过 2,但那一刻上一场已经散了。对应模板里 while 在 rooms += 1 之前。30 秒识别Q1 · 986 Interval List Intersections:给两个各自有序且内部不相交的区间列表,求它们的交集。你的第一反应是哪个模式?
区间 + 双指针。两个列表都已排序,交集是 [max(起点), min(终点)],非空就收下,然后终点小的那一方前进。「两个有序列表」这个形状同时也是第 02 章的信号,但处理对象是区间,模板在本章。
30 秒识别Q2 · 1288 Remove Covered Intervals:删除所有被其他区间覆盖的区间,返回剩余数量。你的第一反应是哪个模式?
区间。排序键是本题全部难点:起点升序、起点相同时终点降序,这样长的排在前面,后面凡是终点不超过当前最大终点的都被覆盖。
30 秒识别Q3 · 55 Jump Game:数组里每个数表示在该位置最多能向前跳几步,判断能否从起点跳到终点。你的第一反应是哪个模式?
贪心,不是本章——每个下标确实定义了一个「可达区间」,看起来很像区间题,但不需要排序也不需要合并:只要一路维护「目前能到的最远位置」,走到某处发现最远位置还不如当前下标就失败。见第 15 章。
每章自测都会混入恰好一道非本章题,防止「读哪章选哪章」的条件反射;题面也一律取自本章未收录的题,避免凭记忆而非凭信号作答。