30 秒识别Q1 · 2115 Find All Possible Recipes from Given Supplies:给一批菜谱、各自的原料表和你手上的现有原料,求最终能做出哪些菜(一道菜也可以是另一道菜的原料)。你的第一反应是哪个模式?
看答案
拓扑排序。「A 是 B 的原料」就是一条有向边,手上的现有原料是入度为 0 的起点,能被剥出来的菜就是做得成的。题面把「依赖」换了个说法而已——认出有向依赖这四个字,模板一行不用改。
判环不需要额外逻辑:能出队的点数少于总点数,剩下的就卡在环里。这一条让「能不能修完所有课」和「给出一种修课顺序」变成同一段代码,只是返回值不同。
全章唯一的难点其实是建图方向。LeetCode 给的 [b, a] 意思是「修 b 之前要先修 a」,所以边是 a → b、indeg[b] += 1。方向反了代码照样能跑,只是答案整个是倒的。
| 题面出现… | 想到 |
|---|---|
| 「先修课 / 前置条件 / 依赖关系」 | 拓扑排序,入度为 0 进队列 |
| 「编译顺序 / 任务调度顺序 / 打包顺序」 | 同上,问的是一种合法线性序 |
| 「判断有没有循环依赖 / 能不能全部完成」 | 拓扑 + 计数判环 |
| 「输出任意一种合法顺序」 | 拓扑(答案不唯一正是它的特征) |
| 「根据给定的单词序推字母表顺序」 | 先从相邻单词比出边,再拓扑(269) |
| 图是有向的且要问顺序 | 拓扑;无向图问连通性是第 12 章 |
同样用队列,第 10 章的 BFS 队列里放的是「所有未访问的邻居」,本章队列里放的是「入度已清零的点」——入度这两个字是分界线。判环也要分清:有向图判环用拓扑(本章),无向图判环用并查集(第 12 章,union 返回 False 即成环)或 DFS 记父节点。只要遍历、不问顺序,回到第 10 章。
■ 【骨架】 不变,闭着眼默写 ■ 【插槽】 随题变化,写题前先问自己填什么
from collections import deque
def topo_order(n, prerequisites):
graph = [[] for _ in range(n)] # 【骨架】邻接表:a -> b 表示"修完 a 才能修 b"
indeg = [0] * n # 【骨架】入度 = 还欠几个前置
for b, a in prerequisites: # 【插槽】题目给的是 [课, 先修课],方向别搞反
graph[a].append(b)
indeg[b] += 1
q = deque(i for i in range(n) if not indeg[i]) # 【骨架】所有零依赖的先入队
order = []
while q: # 【骨架】
cur = q.popleft() # 【骨架】
order.append(cur) # 【插槽】答案:顺序本身 / 只要个数
for nxt in graph[cur]: # 【骨架】
indeg[nxt] -= 1 # 【骨架】它少欠一个了
if not indeg[nxt]: # 【骨架】欠债清零才有资格入队
q.append(nxt) # 【骨架】
return order if len(order) == n else [] # 【插槽】出队数 < n 就是有环
order 而不是布尔值。两道题放一起就是本章的全部内容——这也是本章刻意没有热身题的原因。[b, a] 是「先修 a 才能修 b」,边必须是 a → b。反了之后 207 依然返回 True(有向无环图反向仍无环),但 210 的顺序整个是倒的。n 开满,没有任何依赖的课也要以 0 入度进队列。只遍历 prerequisites 建表,会漏掉从未出现过的课号。len(order) == n 这一句。写成递归 DFS 再捕获「重复访问」,既长又容易把「本次路径上」和「以前访问过」搞混。30 秒识别Q1 · 2115 Find All Possible Recipes from Given Supplies:给一批菜谱、各自的原料表和你手上的现有原料,求最终能做出哪些菜(一道菜也可以是另一道菜的原料)。你的第一反应是哪个模式?
拓扑排序。「A 是 B 的原料」就是一条有向边,手上的现有原料是入度为 0 的起点,能被剥出来的菜就是做得成的。题面把「依赖」换了个说法而已——认出有向依赖这四个字,模板一行不用改。
30 秒识别Q2 · 802 Find Eventual Safe States:有向图中,从某点出发的所有路径最终都能走到终点(出度为 0 的点),求所有这样的安全点。你的第一反应是哪个模式?
拓扑排序。把图反向后,出度为 0 就变成入度为 0,能被剥掉的点就是安全的,剥不掉的卡在环里。「反向建图」是拓扑题的常见变形。
30 秒识别Q3 · 547 Number of Provinces:给一个 n×n 的矩阵表示城市之间是否直接相连,求「省份」(连通块)的个数。你的第一反应是哪个模式?
并查集,不是本章——图是无向的,问的是「谁和谁在一伙」而不是「谁在谁前面」。无向图没有入度这个概念,拓扑排序无从谈起。见 §2 分流条件与第 12 章。
每章自测都会混入恰好一道非本章题,防止「读哪章选哪章」的条件反射;题面也一律取自本章未收录的题,避免凭记忆而非凭信号作答。