EP.09 用 DFS 打通了遞迴的思維,這篇接著講三個不同的 Tree 主題:BFS 層序遍歷(用 Queue 而非遞迴)、BST 的驗證(Binary Search Tree 的隱含約束),以及 LCA 最近公共祖先(Tree 中最優雅的遞迴之一)。
DFS vs BFS:兩種遍歷方式
DFS(深度優先)
一路往深處走,到底再回頭。用遞迴或 Stack 實作。
BFS(廣度優先)
一層一層向外擴,用 Queue(deque) 實作。
「按層」這個特性讓 BFS 天然適合 Level Order Traversal 和「找最短路徑」類的問題。
#102 Binary Tree Level Order Traversal
按照層次,從上到下、從左到右輸出每一層的節點值。
BFS 的標準實作用 collections.deque。關鍵是:每次進入 while loop 時,queue 裡剛好放著「當前層的所有節點」。
為什麼用 deque 而不是 list?
list.pop(0) 是 O(n)(要搬移所有元素),deque.popleft() 是 O(1)。Queue 的 dequeue 操作一定要用 deque。
逐步追蹤:
#98 Validate BST:理解 BST 的真正約束
BST(Binary Search Tree)的定義:左子樹的所有節點值 < 當前節點值 < 右子樹的所有節點值。
注意:是所有節點,不只是直接的左右子節點。
錯誤解法:只比較 node.left.val < node.val < node.right.val,這樣會漏掉全局約束。
正確做法:傳入合法值範圍(min_val, max_val),每往下走一層就縮緊範圍。
上面那棵有問題的樹,用範圍追蹤:
#235 Lowest Common Ancestor(LCA)
給 BST 中的兩個節點 p 和 q,找它們的最近公共祖先(LCA)——兩個節點的共同祖先中,最靠近它們的那個。
利用 BST 的性質:
何時用 DFS,何時用 BFS?
需要「按層」處理
Level Order、找最短路徑
需要「從底部往上」累積結果
Max Depth、Diameter
需要「從頂部往下」傳遞資訊
Validate BST(傳遞範圍)
找路徑、找是否存在
Path Sum、Same Tree
樹非常深(接近線性),怕 stack overflow
退化成 Linked List 的樹
BST 題目的核心是利用大小關係「剪枝」——每次可以丟掉一半,把 O(n) 降到 O(h)。這和 Binary Search 的精神完全一樣:每步都能保證目標「不在那裡」,所以可以安全丟掉。
本篇重點整理
上一篇
EP.09 — Tree & DFS
遞迴的本質,就是信任自己
下一篇
EP.11 — Dynamic Programming
即將推出