力扣刷题#26-0102-二叉树的层序遍历
力扣刷题#26-0102-二叉树的层序遍历
题目
给你二叉树的根节点 root,返回其节点值的层序遍历(即逐层地、从左到右访问所有节点)。
输入: root = [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
输出: [[3],[9,20],[15,7]]
前置知识:BFS vs DFS
中序遍历(DFS)是一条路走到黑再回头。层序遍历(BFS)是一层一层扫过去——像剥洋葱,从外往里。
1 ← 第0层
/ \
2 3 ← 第1层
/ \ \
4 5 6 ← 第2层
/
7 ← 第3层
BFS 输出: [[1], [2,3], [4,5,6], [7]]
BFS 的核心工具是队列——从队头拿一个节点出来,把它的左右孩子塞到队尾。先进先出,天然就是一层一层走。
我的思路
BFS 的基本骨架
queue<TreeNode*> q;
q.push(root);
while (队列不空) {
取出队头
把孩子入队
}
但这样只能把所有节点串成一个长列表 [1,2,3,4,5,6,7],分不出"哪几个是第一层、哪几个是第二层"。
分层的诀窍:sz = q.size()
在每一轮 while 循环开始时,队列里的节点全部属于同一层。取一次 q.size() 存成 sz,然后用 for 循环恰好处理 sz 个节点。循环内新入队的孩子不会影响 sz——天然的"这一层"和"下一层"隔离。
while (队不空) {
int sz = q.size(); // ← 这一层有几个
vector<int> level;
for (int i = 0; i < sz; i++) { // 只取 sz 个
弹出队头 → 记录值
有左孩子 → 入队
有右孩子 → 入队
}
res.push_back(level); // 这一层收工
}
走一遍
3
/ \
9 20
/ \
15 7
| 轮次 | sz | 队列(处理前) | 处理的节点 | level | 队列(处理后) |
|---|---|---|---|---|---|
| 1 | 1 | [3] |
3 | [3] |
[9,20] |
| 2 | 2 | [9,20] |
9, 20 | [9,20] |
[15,7] |
| 3 | 2 | [15,7] |
15, 7 | [15,7] |
[] |
结果:[[3], [9,20], [15,7]] ✅
我的 AC 代码
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
if (!root) return {};
vector<vector<int>> res;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
int sz = q.size();
vector<int> level;
for (int i = 0; i < sz; i++) {
TreeNode* cur = q.front();
q.pop();
level.push_back(cur->val);
if (cur->left) q.push(cur->left);
if (cur->right) q.push(cur->right);
}
res.push_back(level);
}
return res;
}
};
代码逐段解析
第 3 行:空树保护
if (!root) return {};
力扣会传 root = nullptr 的测试用例。没有这行,q.push(nullptr) 之后取出 cur = nullptr,取 cur->val 就直接崩了。
第 6-7 行:初始化
queue<TreeNode*> q;
q.push(root);
根节点入队,一切从这里开始。
第 9 行:外层 while
while (!q.empty()) {
队列不空 = 还有层没处理完。
第 10-11 行:分层核心
int sz = q.size();
vector<int> level;
sz 必须在 for 循环之前取一次。如果写成 for(i=0; i<q.size(); i++),循环里 push 了新节点,q.size() 会持续变大 → 死循环或结果错乱。
第 13-18 行:处理当前层
for (int i = 0; i < sz; i++) {
TreeNode* cur = q.front();
q.pop();
level.push_back(cur->val);
if (cur->left) q.push(cur->left);
if (cur->right) q.push(cur->right);
}
for 循环跑完,当前层的所有节点都取出来了,它们的值进了 level,孩子们进了队列——成为"下一层"。
第 19 行:收尾
res.push_back(level);
一层完事,塞进结果。
踩坑记录
坑 1:空树没判
// ❌
q.push(root); // root = nullptr
// ...
level.push_back(cur->val); // cur = nullptr → 崩
修复:if (!root) return {}; 放在最前面。
坑 2:sz 没提前存
// ❌
for (int i = 0; i < q.size(); i++) { ... } // q.size() 在循环里会变
修复:int sz = q.size(); 在 for 外面取一次。
复杂度分析
| 维度 | 值 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | 每个节点入队一次、出队一次 |
| 空间复杂度 | O(n) | 队列最大存一整层节点 |
关键点总结
| 关键点 | 说明 |
|---|---|
| 核心结构 | 队列——先入先出,天然适配层序遍历 |
| 分层的技巧 | sz = q.size() 在 for 前取一次,循环内新入队不影响 |
| BFS 模板 | while(队不空) { sz取一次; for(0..sz) { 弹出+记录+孩子入队 } } |
| 空树保护 | if (!root) return {}; |
本文档由 AI 辅助生成,作者提供问题,思路和代码,AI仅负责文本修饰,综合获得以上内容。

浙公网安备 33010602011771号