一.题目
103. 二叉树的锯齿形层序遍历 - 力扣(LeetCode)

二.思路讲解
2.1 思路讲解
锯齿形层序遍历 是在普通层序遍历的基础上,增加一个方向标志,用来控制每一层节点的输出顺序。
-
核心思路 :使用队列进行层序遍历,同时维护一个布尔变量
flag(或leftToRight),初始为true表示从左到右。 -
每层处理 :记录当前层的节点数,依次取出节点,将节点值存入临时数组。若当前方向为从左到右,则直接存入;若为从右到左,则存入后需要反转该层的结果。
-
方向切换 :每一层处理完毕后,将
flag取反,即下一层的方向与当前层相反。 -
结果收集:将每层处理后的数组依次加入最终结果集。
三.代码演示
cpp
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> zigzagLevelOrder(TreeNode* root)
{
vector<vector<int>> ret;
//如果为空
if(root == nullptr) return ret;
queue<TreeNode*> q;
q.push(root);
bool control = true;//标记位
while(q.size())
{
int sz = q.size();
vector<int> tmp;
for(int i = 0;i < sz;i++)
{
TreeNode* t = q.front();//取出队头
q.pop();//删除队头
tmp.push_back(t->val);
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
//为true不逆置,false逆置
if(control == false)
{
reverse(tmp.begin(),tmp.end());
control = true;
}
else
{
control = false;
}
ret.push_back(tmp);
}
return ret;
}
};
四.代码讲解
一、数据结构与初始化
-
ret:二维向量,存储最终的锯齿形层序遍历结果,每个子向量代表一层的节点值。 -
q:队列,用于按层顺序暂存待处理的节点。队列的先进先出特性保证了同层节点从左到右的顺序(但后续通过反转实现锯齿形)。 -
control:布尔变量,标记当前层是否需要反转。初始为true,表示第一层从左到右(不反转);后续每处理完一层后切换。
二、边界处理
如果根节点 root 为空,直接返回空结果集 ret。
三、主循环:逐层处理
当队列不为空时,表示还有节点未处理,继续循环。
1. 记录当前层节点数
int sz = q.size();
此时队列中存放的恰好是当前层的所有节点(上一层的子节点已全部入队),sz 即为本层节点个数。
2. 处理当前层节点
创建一个临时向量 tmp 用于存放本层的节点值。 循环 sz 次:
-
取出队头节点
t,并将其值加入tmp。 -
将
t的左子节点和右子节点(若存在)依次入队,保证下一层节点按从左到右的顺序进入队列。
3. 根据方向决定是否反转
-
如果
control == false,说明当前层应该从右到左输出,因此将tmp反转。 -
反转后,将
control置为true,表示下一层方向变回从左到右。 -
如果
control == true,则当前层不反转,直接将control置为false,表示下一层需要反转。
4. 存储本层结果
将处理后的 tmp 加入 ret。
四、关键细节
-
方向交替 :通过
control在true和false之间来回切换,实现了锯齿形遍历。 -
反转时机:只有在需要从右到左输出的层才反转临时数组,反转后立即切换标志,确保下一层方向正确。
-
队列长度固定 :在进入内层循环前先记录
sz,确保只处理当前层的节点,避免将下一层节点提前混入。
五、流程图
