30 秒识别Q1 · 572 Subtree of Another Tree:判断一棵树是不是另一棵树的子树。你的第一反应是哪个模式?
看答案
树的递归。外层递归找候选根,内层递归判「两棵树是否完全相同」——两个模板 A 嵌套。看到「结构相同」就该想到 isSame(a, b) 这个经典返回值。
把「返回值的含义」写在纸上(深度?子树是否合法?子树的最大路径和?),剩下的三件事会自动落位:空节点返回什么(地基)、怎么合并左右的返回值(当前节点做什么)、答案是不是就是根节点的返回值。
最容易卡住的一类是返回值 ≠ 答案:543 的返回值是深度、答案是直径;124 的返回值是「向上贡献的单边路径和」、答案是「经过某点的整条路径和」。这类题一律用 nonlocal best 把答案挂在递归外面。
| 题面出现… | 想到 |
|---|---|
| 「深度 / 高度 / 直径 / 是否平衡」 | 后序递归,返回值是深度(模板 A) |
| 「层 / 每一层 / 最短路径 / 右视图」 | BFS 队列,按层出队(模板 B) |
| 「BST」+「第 K 小 / 有序输出」 | 中序遍历天然升序 |
| 「验证 BST」 | 带上下界递归,不能只和父节点比 |
| 「最近公共祖先 LCA」 | 后序:左右都非空则当前就是答案;BST 可用值域直接下降 |
| 「前序 + 中序构造」「序列化 / 反序列化」 | 用中序定位划分点 / 前序 + 空标记 |
要枚举所有路径 / 所有方案并且需要撤销选择,那是回溯(第 09 章),树只是它的递归载体。网格和邻接表上的 BFS/DFS 属于第 10 章——区别在于树没有环、不需要 visited,一旦要判重就说明你面对的是图。「层序」和「多源最短步数」共用队列骨架,但树的层序不需要 visited。还有一个同名陷阱:树里说「有序」指的是 BST 的中序,和有序数组(第 05 章的二分)、有序链表(第 06 章的合并、第 08 章的 K 路归并)不是一回事——BST 的有序性藏在结构里,你得走一遍中序才能看见它。
■ 【骨架】 不变,闭着眼默写 ■ 【插槽】 随题变化,写题前先问自己填什么
def max_depth(root):
if not root: # 【骨架】空节点的答案 —— 递归的地基
return 0 # 【插槽】空树返回什么
left = max_depth(root.left) # 【骨架】
right = max_depth(root.right) # 【骨架】
return 1 + max(left, right) # 【插槽】当前节点怎么合并左右的返回值
nonlocal 挂在外面。from collections import deque
def level_order(root):
if not root:
return []
q, out = deque([root]), [] # 【骨架】
while q: # 【骨架】
size = len(q) # 【骨架】先固定这一层的人数,再开始出队
level = [] # 【插槽】这一层要收集什么
for _ in range(size): # 【骨架】
node = q.popleft() # 【骨架】
level.append(node.val) # 【插槽】
if node.left:
q.append(node.left) # 【骨架】
if node.right:
q.append(node.right) # 【骨架】
out.append(level) # 【插槽】每层一组 / 只要最后一层 / 只要层数
return out
size = len(q) 这一行是全部:先固定住这一层有几个人,再开始出队,否则新入队的下一层会混进来。l + r 的最大值。见 §1 第二段与翻车点①。depth 返回 -1 表示「已经不平衡」,一次遍历搞定——剪枝藏在返回值里。reverse 即可,199(右视图)取每层最后一个,都是同一个骨架。(lo, hi) 上下界往下传。只比父节点的写法会放过 [5,4,6,null,null,3,7] 这种用例——模板测试里专门留了这条断言。nonlocal 记。543 想明白了,这道只是把「长度」换成「和」。nonlocal 变量。node.left.val < node.val 只保证局部有序。必须把祖先施加的上下界一路传下去。len(q)——循环里直接 while q 逐个出队,会把下一层的节点混进当前层。凡是要「按层」的输出,第一行永远是 size = len(q)。is_balanced 里对每个节点调用 depth,最坏是 O(n²)。用「返回 -1 表示已失衡」把两件事合并成一次遍历。setrecursionlimit」是加分项。30 秒识别Q1 · 572 Subtree of Another Tree:判断一棵树是不是另一棵树的子树。你的第一反应是哪个模式?
树的递归。外层递归找候选根,内层递归判「两棵树是否完全相同」——两个模板 A 嵌套。看到「结构相同」就该想到 isSame(a, b) 这个经典返回值。
30 秒识别Q2 · 199 Binary Tree Right Side View:从右侧看一棵二叉树,返回从上到下能看到的节点值。你的第一反应是哪个模式?
层序 BFS(模板 B)。每层只取最后一个,size = len(q) 那行的直接应用。「右视图 / 每层最大值 / 层平均数」全是同一道题换皮。
30 秒识别Q3 · 200 Number of Islands:给一个由 '1'(陆地)和 '0'(水)组成的网格,数出岛屿的个数。你的第一反应是哪个模式?
图的 BFS/DFS,不是本章——网格是图不是树,会绕回来,所以必须有 visited(或就地改成 '0')。树的递归之所以不用判重,是因为树天然无环。见第 10 章。
每章自测都会混入恰好一道非本章题,防止「读哪章选哪章」的条件反射;题面也一律取自本章未收录的题,避免凭记忆而非凭信号作答。