LeetCode 222 Count Complete Tree Nodes 要求計算完全二叉樹的節點總數。根據維基百科定義:完全二叉樹除最後一層外,每一層都被完全填滿,且最後一層的所有節點都靠左排列。若樹高為 h,最後一層節點數介於 1 到 2ʰ 之間。
最直觀的做法是遍歷整棵樹,例如前序遍歷收集所有節點再計數:
public class Solution {
public int countNodes(TreeNode root) {
List<TreeNode> list = preOrder(root);
return list.size();
}
public List<TreeNode> preOrder(TreeNode root) {
List<TreeNode> list = new ArrayList<>();
if (root == null) return list;
list.add(root);
if (root.left != null) list.addAll(preOrder(root.left));
if (root.right != null) list.addAll(preOrder(root.right));
return list;
}
}
此解法時間複雜度 O(n),空間複雜度 O(n)(遞歸棧 + 列表),在節點數極大時會超時。
完全二叉樹的關鍵特性:左子樹高度恆 ≥ 右子樹高度,且左右子樹至少有一棵是滿二叉樹。
每次遞歸只深入一邊,高度計算僅沿左/右邊緣向下,單次高度 O(log n),遞歸深度 O(log n),總時間複雜度 O(log² n),空間複雜度 O(log n)(遞歸棧)。
public class Solution {
public int countNodes(TreeNode root) {
if (root == null) return 0;
int leftH = height(root.left);
int rightH = height(root.right);
if (leftH == rightH) {
// 左子樹滿,節點數 2^leftH - 1 + 1(根) + 右子樹遞歸
return (1 << leftH) + countNodes(root.right);
} else {
// 右子樹滿,節點數 2^rightH - 1 + 1(根) + 左子樹遞歸
return (1 << rightH) + countNodes(root.left);
}
}
private int height(TreeNode node) {
int h = 0;
while (node != null) {
h++;
node = node.left; // 完全二叉樹最左路徑即高度
}
return h;
}
}
1 << h 等價於 2ʰ,避免 Math.pow 浮點誤差。| 解法 | 時間複雜度 | 空間複雜度 | 備註 |
|---|---|---|---|
| 前序/中序/層序遍歷 | O(n) | O(n) | 超時風險 |
| 利用完全樹性質遞歸 | O(log² n) | O(log n) | 推薦解法 |
| 迭代版優化 | O(log² n) | O(1) | 去除遞歸棧 |
掌握此題核心在於「識別滿子樹並直接計算」,同類技巧常見於完全二叉樹、堆相關題目。