
本文详解 LeetCode「检查二叉树是否为完全二叉树」问题中 BFS 实现的关键逻辑漏洞,重点修复 second_bfs 函数未被调用返回、层级判断错误、空节点处理不严谨等问题,并提供简洁健壮的最终解法。
本文详解 leetcode「检查二叉树是否为完全二叉树」问题中 bfs 实现的关键逻辑漏洞,重点修复 `second_bfs` 函数未被调用返回、层级判断错误、空节点处理不严谨等问题,并提供简洁健壮的最终解法。
在解决 LeetCode 958. Check Completeness of a Binary Tree 时,一个常见误区是:误以为 BFS 层序遍历本身就能自然暴露“非完全性”,而忽略了必须显式捕获并传播布尔返回值。原始代码中,second_bfs(root) 被调用但其返回值被直接丢弃,函数末尾无条件 return True,导致即使内部检测到 node.right and not node.left(违反完全二叉树定义的核心条件),结果仍恒为 True。
更深层的问题在于逻辑分层混乱:
- 第一次 BFS(
bfs_search)仅用于计算树深度,却冗余存储整棵树节点,效率低且易出错; -
tree_depth = len(result) - 2的硬编码依赖result结构,缺乏鲁棒性; -
second_bfs中if len(queue) != 2**(depth)的判断对象错误(应为当前层节点数,而非队列剩余长度); -
break_indicator状态机设计复杂,且未覆盖“某节点左空右非空”后立即终止的场景。
✅ 正确思路应遵循完全二叉树的定义:
层序遍历中,一旦出现空节点,则其后所有节点必须为空。
因此,最简、最可靠的 BFS 实现是单次层序遍历 + 首次空节点标记:
from collections import deque
from typing import Optional
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def isCompleteTree(self, root: Optional[TreeNode]) -> bool:
if not root:
return True
queue = deque([root])
found_null = False # 标记是否已遇到第一个空节点
while queue:
node = queue.popleft()
if node is None:
found_null = True
else:
# 当前节点非空,但之前已出现空节点 → 违反完全性
if found_null:
return False
# 正常入队左右子节点(允许为 None)
queue.append(node.left)
queue.append(node.right)
return True
? 关键说明:
- 将
None显式入队,使层序序列严格对应完全二叉树的理想数组表示(LeetCode 输入格式即如此); -
found_null一旦置为True,后续任何非空节点都直接返回False; - 无需预计算深度、无需分阶段 BFS,时间 O(n),空间 O(w)(w 为最大宽度),逻辑清晰且不易出错。
⚠️ 注意事项:
- 原始代码中
nonlocal depth和多层嵌套逻辑大幅增加维护成本,应优先选择扁平化、语义明确的实现; - 切勿在递归/BFS 中忽略函数返回值——这是调试此类“看似执行却无效果”问题的第一检查项;
- 对于树结构验证题,先写测试用例(如
[1,2,3,4,5,null,7])手动模拟层序过程,比盲调代码更高效。
综上,完全二叉树的 BFS 验证本质是“空节点守门员”问题:守好第一个 None 出现的位置,之后绝不允许“失守”。抓住这一核心,即可写出简洁、正确、可扩展的工业级解法。










