当前位置: 首页 > news >正文

二叉树——队列bfs专题

1.N叉树的层序遍历

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

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

class Node 
{
public:
    int val;
    vector<Node*> children;
};

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

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

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进行判断,如果是偶数就插入反转之后的数组,如果奇数则直接插入即可。

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.在每个树行中找最大值

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

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

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.

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;
    }
};

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

相关文章:

  • Docker容器中的ubuntu apt update报错 解决办法
  • 【58】编程技巧:单片机编程命名规范
  • Oracle数据库数据编程SQL<4.3 事务的补充内容(了解)>
  • 十、C++速通秘籍—多进程
  • 牛客春招刷题训练营 算法 Java 3月27日 杨辉三角的变形 计算日期到天数转换 而后单调
  • 详细介绍一下Vue3的实现原理?
  • Codecademy—— 交互式编程学习的乐园
  • leetcode215.数组中的第k个最大元素
  • intel-xpu-backend-for-triton绕过pytorch直接调用Unified-Runtime
  • 小程序31-wxml语法-setData() 修改数据
  • RTC实时时钟M41T11M6F国产替代FRTC4111S
  • vue3如何批量设置每个vue页面的defineOptions的name
  • Web Workers 技术解析与应用
  • # 基于 OpenCV 的人脸识别实战:从基础到进阶
  • 贪心进阶学习笔记
  • Elasticsearch简介及索引库操作
  • 全新开源PHP轻量级活码管理系统|支持二维码动态更新与自动失效机制
  • 【力扣hot100题】(064)在排序数组中查找元素的第一个和最后一个位置
  • 【Tauri2】015——前端的事件、方法和invoke函数
  • Docker常用操作教程
  • 网站建设对促进部门工作的益处/互联网推广营销
  • 免费打开的网站/百度网址安全中心怎么关闭
  • 做号网站/免费做网站网站的软件
  • 公共部门网站建设维护/上海网站排名优化怎么做
  • 门户网站系统源码/广州seo成功案例
  • 网站建设项目分期/厦门网站到首页排名