二叉树——队列bfs专题

1.N叉树的层序遍历

我们之前遇到过二叉树的层序遍历,只需要用队列先进先出的特性就可以达到层序遍历的目的。

而这里不是二叉树,也就是说让节点的孩子入队列时不仅仅是左右孩子了,而是它的所有孩子。而我们看这棵多叉树的构造,它的孩子是存储在数组中的。所以我们在让孩子入队时只需要依次让数组中的所有节点入队列即可。

cpp 复制代码
class Node 
{
public:
    int val;
    vector<Node*> children;
};

而这道题的要求是返回一个二维数组,数组的元素就是每一层的层序遍历结果。

我们关键点就在于如果确定元素属于那一层,方法就是在进行层序遍历前,我们先统计该队列的大小,大小即使这一层元素的个数,当这个数变为0,表示这一层的元素已经统计完了,这时队列中的就是下一层的元素了。此时重复求大小和层序遍历的过程即可。

cpp 复制代码
class Solution 
{
public:
    vector<vector<int>> levelOrder(Node* root) 
    {
        if(root == nullptr) return {};

        queue<Node*> q;
        q.push(root);
        vector<vector<int>> ret;

        int currentFloorSize = 0;
        while(!q.empty())
        {
            vector<int> currentFloor;
            currentFloorSize = q.size();
            while(currentFloorSize--)
            {
                Node* head = q.front(); //获取队头元素
                for(int i=0; i<head->children.size(); ++i) //让队头孩子入队
                {
                    q.emplace(head->children[i]);
                }
                currentFloor.emplace_back(head->val);//保存队头val
                q.pop();//出队
            }
            ret.emplace_back(currentFloor);
        }
        return ret;
    }
};

2.二叉树的锯齿形层序遍历

依旧是二叉树的层序遍历,只不过在遍历的时候有顺序之分,奇数层从左到右,偶数层从右到左。

解法依旧是先采取正常的层序遍历,多定义一个flag变量用了记录当前是奇数还是偶数。当把这一行统计完毕后,在将该结果插入到数组之前,先对flag进行判断,如果是偶数就插入反转之后的数组,如果奇数则直接插入即可。

cpp 复制代码
class Solution 
{
public:
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) 
    {
        if(root == nullptr) return {};
        
        // 根节点入队列
        queue<TreeNode*> q;
        q.emplace(root);
        vector<vector<int>> ret;

        int currentFloorSize =0;
        int flag = 1; // 遍历层的方向,奇数层left->right, 偶数层right->left
        while(!q.empty())
        {
            currentFloorSize = q.size();
            vector<int> currentFloorEele;
            while(currentFloorSize--)
            {   
                // 保存节点数据
                TreeNode* head = q.front();
                q.pop();
                currentFloorEele.emplace_back(head->val);

                // 孩子入队列
                if(head->left) q.emplace(head->left);
                if(head->right) q.emplace(head->right);
            }
            if(flag % 2 == 0)
                reverse(currentFloorEele.begin(), currentFloorEele.end());
            ret.emplace_back(currentFloorEele);
            flag++;
        }
        return ret;
    }
};

3.在每个树行中找最大值

题目要求返回一个数组,数组的元素都是二叉树每一层的最大值。

解法:我们只需要在进行层序遍历的过程中,进行最大值的统计即可。当遍历完该层后,直接保存最大值即可。

cpp 复制代码
class Solution 
{
public:
vector<int> largestValues(TreeNode* root) 
    {
        if(root == nullptr) return {};

        queue<TreeNode*> q;
        q.emplace(root);
        vector<int> ret;
        
        int currentFloorSize = 0;
        while(!q.empty())
        {
            currentFloorSize = q.size();
            int maxVal = INT_MIN;
            while(currentFloorSize--)
            {
                auto head = q.front();
                q.pop();
                
                maxVal = max(maxVal, head->val);
                if(head->left) q.emplace(head->left);
                if(head->right) q.emplace(head->right);
            }
            ret.emplace_back(maxVal);
        }
        return ret;
    }
};

4.二叉树最大深度

返回所有层中最宽的。其中,我们只需要看每一层的最左和最右即可,其中也要计算中间的空节点。

解法:我们将二叉树以顺序方式进行存储,存储对用的根节点以及对应的下标。其实就是堆的存储方式。当我们根节点从0开始,他的左右孩子可以通过2*x+1,2*x+2得来。这样下来,每一层的宽度其实就是最左与最右节点的下标的差值+1.

cpp 复制代码
class Solution 
{
public:
    int widthOfBinaryTree(TreeNode* root) 
    {
        vector<pair<TreeNode*, unsigned int>> LevelSize; // 模拟队列,将二叉树以顺序结构存储
        unsigned int ret = 0; // 统计结果
        LevelSize.emplace_back(root, 0);

        while(!LevelSize.empty())
        {
            // 取出该层的首尾节点,并更新结果
            auto& [x1, y1] = LevelSize[0];
            auto& [x2, y2] = LevelSize.back();
            ret = max(ret, y2 - y1 + 1);

            // 让孩子入队
            vector<pair<TreeNode*, unsigned int>> tmp; // 临时存储下一层的节点,最后覆盖原队列
            for(auto& [x, y] : LevelSize)
            {
                if(x->left) tmp.emplace_back(x->left, y * 2 + 1);
                if(x->right) tmp.emplace_back(x->right, y * 2 + 2);
            }

            // 更新层
            LevelSize = tmp;
        }
        return ret;
    }
};

说明:我们这里使用数组来模拟的队列,因为我们让孩子入队列后得头删上一层的元素,在数组中头删消耗比较大,所以我们可以用一个临时数组来统计下一层的元素,之后用临时数组覆盖原数组即可。

相关推荐
DASXSDW12 分钟前
NET性能优化-使用RecyclableBuffer取代RecyclableMemoryStream
java·算法·性能优化
kfepiza18 分钟前
CAS (Compare and Swap) 笔记251007
java·算法
墨染点香1 小时前
LeetCode 刷题【103. 二叉树的锯齿形层序遍历、104. 二叉树的最大深度、105. 从前序与中序遍历序列构造二叉树】
算法·leetcode·职场和发展
啊我不会诶1 小时前
23ICPC澳门站补题
算法·深度优先·图论
Brookty2 小时前
【算法】二分查找(一)朴素二分
java·学习·算法·leetcode·二分查找
黑色的山岗在沉睡3 小时前
LeetCode 2761. 和等于目标值的质数对
算法·leetcode·职场和发展
bawangtianzun3 小时前
重链剖分 学习记录
数据结构·c++·学习·算法
ChoSeitaku7 小时前
NO.14数据结构红黑树|树高|转化4阶B树|插入操作|删除操作
数据结构·b树
T1an-17 小时前
力扣70.爬楼梯
算法·leetcode·职场和发展
T1an-17 小时前
力扣169.多数元素
数据结构·算法·leetcode