102. 二叉树的层序遍历(Binary Tree Level Order Traversal)

难度:中等 | 主题:二叉树、BFS、队列 ⭐常见

题目

给你二叉树的根节点 root,返回其节点值的层序遍历(逐层从左到右访问)。

示例

 
输入:root = [3,9,20,null,null,15,7]
 
输出:[[3],[9,20],[15,7]]
 

思路

先讲个故事:地铁站台广播

想象你在地铁调度中心,监控着一条线路上的所有站台。

调度员的口号是:

“当前站的乘客全部上车后,列车才开到下一站。”

这和层序遍历一模一样——先把当前层的所有节点”放行”完,才进入下一层。而实现的秘密武器就是:队列(先进先出)


引导式推导:从手动模拟到 BFS 模板

场景:手动层序遍历以下树

 
      3
 
     / \
 
    9   20
 
       /  \
 
      15   7
 

第 1 步:queue = [3],处理 3,让它的子节点 9、20 进队

  • 输出:[3]

第 2 步:queue = [9, 20],这俩都要处理(都在同一层),然后让它们的子节点进队

  • 输出:[3], [9, 20]

第 3 步:queue = [15, 7],处理掉

  • 输出:[3], [9, 20], [15, 7]

关键洞察:怎么知道哪些节点属于同一层?

答:在处理当前层之前,先记录队列长度 level_size = len(queue)

接下来只弹出 level_size 个节点——这些就是当前层的全部节点。新入队的下一层节点,不在本轮处理范围内。


graph TD

    subgraph 队列演变

        direction LR

        s1["初始<br/>[3]"] --> s2["处理3后<br/>[9,20]"]

        s2 --> s3["处理9,20后<br/>[15,7]"]

        s3 --> s4["处理15,7后<br/>[]"]

    end

    tree["树"] --> |层序| result["结果<br/>[[3],[9,20],[15,7]]"]

BFS 层序模板(四步走)

 
1. 根节点入队列
 
2. while 队列不为空:
 
3.   level_size = len(队列)     ← 记录当前层大小
 
4.   for _ in range(level_size): ← 只处理当前层
 
5.     出队一个节点,记录值
 
6.     左右子节点入队
 

代码

 
from collections import deque
 
def levelOrder(self, root):
 
    if not root:
 
        return []
 
    result = []
 
    q = deque([root])
 
    while q:
 
        level_size = len(q)         # 关键:先固定当前层大小
 
        level = []                  # 存当前层值
 
        for _ in range(level_size):
 
            node = q.popleft()      # O(1) 出队
 
            level.append(node.val)
 
            if node.left:
 
                q.append(node.left)
 
            if node.right:
 
                q.append(node.right)
 
        result.append(level)
 
    return result
 

复杂度

指标解释
时间O(n)每个节点出队入队恰好一次
空间O(w)w 为树的最大宽度,队列最多存一层节点

实战考量

频率分析

出现在:字节/美团/阿里 高频。层序遍历是 BFS 的标准模板,约 50% 的树 BFS 题可以套这个模板微调。关键点在于:level_size 为什么要提前记录?

延伸思考

Q:为什么 level_size = len(q) 要写在 for 循环外面?

A:因为在 for 循环中队列会不断有新节点入队(子节点),len(q) 会动态变化。如果在 for 里直接写 range(len(q)),Python 的 range 只在初始化时求值一次,所以实际上也正确。但写成变量更清晰。

Q:不用队列,用两个列表交替存储行不行?

A:可以。用 cur_levelnext_level 两个列表,每轮处理完一轮就交换。这在某些变体题(如之字形)中会更方便。

Q:如果要求每层平均值呢?

A:在 level 求和,除以 level_size。对应 637 题。

Q:如果要求每层最大值呢?

A:遍历每层时记录 max。对应 515 题。

Q:如果要求自底向上层序遍历呢?

A:正常 BFS,最后 result.reverse() 或在每次插入时 result.insert(0, level)。对应 107 题(二叉树层序遍历 II)。

Q:199二叉树的右视图 怎么用层序做?

A:每层只取最后一个节点的值。还是在 for 循环中,判断 i == level_size - 1 时记录。

易错点

  • 空树的处理:if not root: return []

  • level_size = len(q) 必须在处理当前层之前记录

  • Python 中 list.pop(0) 是 O(n),要用 collections.deque.popleft() 优化到 O(1)


生活类比

层序遍历 → 地铁站台广播

请先上车的乘客往车厢中部走”——广播只说”当前站”的乘客,不关心下一站谁在等车。

队列就是站台闸机:当前层的乘客(节点)全部通过闸机后,闸机才放行下一层的人。

level_size 就是广播员手里的当前站人数清单——拿着清单清点,不会把下一站的人算进来。


相关题目

题目关系
103二叉树的锯齿形层序遍历层序变体,奇数层反转方向
199二叉树的右视图每层只取最右节点
107 二叉树的层序遍历 II自底向上层序,最后反转结果
515 在每个树行中找最大值每层记录最大值
637 二叉树的层平均值每层求和取均值

→ 返回题单:LeetCode学习路线图 > 五、二叉树

速记卡(面试闪卡)

Q1:一句话讲清「102. 二叉树的层序遍历(Binary Tree Level Order Traversal)」到底是什么?

A:逐层从左到右访问二叉树节点,返回每层的节点值列表,用队列做 BFS。

Q2:题目:地铁站台广播(level order / BFS) —— 怎么理解?

A:像地铁调度:“当前站乘客全上车,列车才开下一站”。层序遍历就是先把一整层节点放行完再进下一层——实现靠先进先出的队列。

Q3:思路:level_size 锁层(BFS with level size) —— 怎么理解?

A:处理当前层前先记下 level_size = len(queue),只弹出这么多个节点;新入队的子节点算下一层。像广播员手里”当前站人数清单”,清点时不会把下一站的人算进来。

Q4:代码:deque 出队(queue / popleft) —— 怎么理解?

A:根入 deque,while q 里取 level_size,循环 popleft 取值、把左右子入队,本层收进 result。注意用 deque.popleft() 而非 list.pop(0)(后者 O(n))。

Q5:复杂度与实战(O(n) time, O(w) space) —— 怎么理解?

A:时间 O(n)(每节点出入队一次),空间 O(w)(w 为最大宽度)。约 50% 树 BFS 可套此模板;变体:之字形(103)、右视图(199)、每层最大(515)都靠它。

Q6:核心速记主线有哪些?

  • 题目:逐层返回节点值列表,BFS

  • 思路:队列按层处理,先记 level_size 锁层

  • 代码:deque.popleft 取值,子节点入队

  • 复杂度:时间 O(n)、空间 O(w)

  • 实战:之字形/右视图/层最大皆其变体

口诀

A:队列先进亦先出,

size 锁层不串步;

逐层扫描稳如故,

右视之字皆能数。

相关链接