前言
本文将会向你介绍有关队列+宽度优先搜索的题目:N叉树的层序遍历、二叉树最大宽度、在每个树中找最大值、二叉树的锯齿形层序遍历
N叉树的层序遍历
题目要求
题目解析
根据题意,需要把一个N叉树的节点值进行层序遍历并返回,层序遍历(按照树的层级顺序逐层访问每个节点,从上到下,从左到右进行遍历)
使用队列进行宽度优先搜索的原因:
1、先进先出:队列遵循先进先出原则,这跟我们从上到下每层依次遍历的访问顺序相符,先进先出就能确保每一层的节点都在前一层的节点之后被访问
2、动态管理节点:在遍历过程中,遍历该层节点结束,我们就需要移除该层节点,添加下一层节点,队列允许我们在遍历时将当前节点添加到队列的末尾,同时能从前端取下访问的节点
3、层级控制:通过使用队列,可以轻松控制当层的节点数量,可以将其子节点加入队列,并在处理完当前层的所有节点后再处理下一层的节点。
这道题也可以说是宽搜的模板,要求理解+记忆
总体思路(忽略一些细节):
先将根节点加入到队列中,然后遍历该层的当前节点的所有子节点,并将被遍历到的节点pop并保存,然后将该层(根节点)的每个节点的子节点添加到队列当中,总的来说,就是先统计该层的节点,再统计该层节点的所有子节点,这样就能统计遍历出N叉树的所有节点
代码如下
class Solution {
public:
vector<vector<int>> levelOrder(Node* root)
{
vector<vector<int>> ret;
queue<Node*> q;
q.push(root);
if(root == nullptr) return ret;
while(q.size())
{
int sz = q.size();
vector<int> tmp;
for(int i = 0; i < sz; i++)
{
Node* t = q.front();
q.pop();
tmp.push_back(t->val);
for(Node* child : t->children)
{
q.push(child);
}
}
ret.push_back(tmp);
}
return ret;
}
};
二叉树最大宽度
题目要求
题目解析
本题的要求是求出二叉树所有层中最大的宽度,有了第一题的基础,那么这道题也用宽搜解决。 注意:这个宽度并不是示例中每一层的节点数,而是将每层的第一个节点和最后一个节点之间的nullptr都需要补齐后的宽度。 比如这棵二叉树的最大宽度就是4
代码如下
class Solution {
public:
int widthOfBinaryTree(TreeNode* root)
{
vector<pair<TreeNode*, unsigned int>> q;
q.push_back({root, 1});
unsigned int ret = 0;
while(q.size())
{
auto& [x1, y1] = q[0];
auto& [x2, y2] = q.back();
ret = max(ret, y2 - y1 + 1);
vector<pair<TreeNode*, unsigned int>> tmp;
for(auto& [x, y] : q)
{
if(x->right) tmp.push_back({x->right, y * 2});
if(x->left) tmp.push_back({x->left, y * 2 + 1});
}
q = tmp;
}
return ret;
}
};
在每个树中找最大值
题目要求
题目解析
题目要求返回每一层的最大值,该题的思路与前两道相似,属于简单题 利用层序遍历,遍历每一层所有节点,算出最大值 注意:-231 <= Node.val <= 231 - 1
代码如下
class Solution {
public:
vector<int> largestValues(TreeNode* root)
{
queue<TreeNode*> q;
vector<int> ret;
if(root == nullptr) return ret;
q.push(root);
while(q.size())
{
int tmp = INT_MIN;
int sz = q.size();
for(int i = 0; i < sz; i++)
{
auto t = q.front();
q.pop();
tmp = max(tmp, t->val);
if(t->right) q.push(t->right);
if(t->left) q.push(t->left);
}
ret.push_back(tmp);
}
return ret;
}
};
二叉树的锯齿形层序遍历
题目要求
题目解析
锯齿形层序遍历也就是在层序遍历的基础上:偶数反着来,奇数正常来
加一个标志位,用来表示该层是奇数层还是偶数层即可,具体思路与前些题相似,不再多赘述
代码如下
class Solution {
public:
vector<vector<int>> zigzagLevelOrder(TreeNode* root)
{
vector<vector<int>> ret;
int flag = 1;
if(root == nullptr) return ret;
queue<TreeNode*> q;
q.push(root);
while(q.size())
{
int sz = q.size();
vector<int> tmp;
for(int i = 0; i < sz; i++)
{
auto t = q.front();
q.pop();
if(flag % 2 != 0)
tmp.push_back(t->val);
else
tmp.insert(tmp.begin(), t->val);
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
ret.push_back(tmp);
flag++;
}
return ret;
}
};