基础算法:队列+BFS

目录

一、N叉树的层序遍历

二、二叉树的锯齿形层序遍历

三*、二叉树的最大宽度

四、在每个树行中找最大值


队列仿佛就是为了BFS而诞生的

一、N叉树的层序遍历

429. N 叉树的层序遍历 - 力扣(LeetCode)

queue,拿出队头元素,这个元素孩子进队

如何分层?记录每层元素

一次循环仅处理该层元素,处理细节即让该层元素入一维数组,同时让该层元素的孩子(如果存在)就入队列。

class Solution {
public:
    vector<vector<int>> levelOrder(Node* root) {
        vector<vector<int>> ret;
        queue<Node*> q;//队列处理节点
        
        //特殊情况处理
        if(root==nullptr)return ret;

        q.push(root);
        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* children:t->children)
                {
                    if(children!=nullptr)
                    q.push(children);
                }
            }
            //记录该层元素
            ret.push_back(tmp);
        }
        return ret;
    }
};

二、二叉树的锯齿形层序遍历

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

这种解法似乎在,周期为二的相邻两次处理步骤不同的情境(就是一次为a行为,下一次为b行为,再下一次为a行为....)中很常见

当是偶数行的时候我们将数组逆序即可,这借助rerverse很容易做到,其实思考到了偶数行需要逆序,自然会想到标记位,还有rerverse逆序数组。

class Solution {
public:
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
        vector<vector<int>> ret;
        queue<TreeNode*> q;
        if(root==nullptr)return ret;
        q.push(root);
        //标记位,初始值设置为一个奇数
        int level =1;
        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);
            }
            if(level%2==0)reverse(tmp.begin(),tmp.end());
            ret.push_back(tmp);
            //更新!!!
            ++level;
        }
        return ret;
    }
};

三*、二叉树的最大宽度

662. 二叉树最大宽度 - 力扣(LeetCode)

我们可以给二叉树结点编号,这样我们通过编号相减,很容易就能得到长度

找最左最右结点,通过q.front和q.back很容易实现

需要注意的是,根节点编号0和1的孩子结点的编号的计算规则不一样

编号0:左孩子2x+1,右孩子2x+1

编号1:左孩子2x,右孩子2x+1

此外需要注意的是,二叉树每一层的结点个数都是指数级增长的,如果做了加减乘除这样的操作,都可能会有越界的风险,比如该方法当层数达到1500层,下标可能会溢出

虽然下标可能会溢出,导致回绕(溢出后从负数范围最大值开始)但是因为我们做的是相减的操作,即使下标溢出变成了负数,在相减时求得的结果会修正为二者之间的距离,那么依然正确

比如这里char类型是正数最大到达127,再加一就会溢出,回绕到-128,-128-127其实是1,为啥呢,因为char范围最大存储8位,超过的会截断

截断后00000001,即 1(因为超出 char 范围,只保留低 8 位)

但是如果是溢出一圈之后又溢出,再相减,那么就会出错,但题目说明数据在32位带符号整数范围内,所以这种情况肯定是不会出现的不用担心。

当然,为了防止溢出也可以直接采用unsigned int

class Solution {
public:
    int widthOfBinaryTree(TreeNode* root) {
        vector<pair<TreeNode*,unsigned int>> q;
        q.push_back({root,1});
        //max函数要求两个参数类型相同,所以ret也设置成unsigned int
        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->left)tmp.push_back({x->left,y*2});
                if(x->right)tmp.push_back({x->right,y*2+1});
            }
            q=tmp;
        }
        return ret;
    }
};

四、在每个树行中找最大值

515. 在每个树行中找最大值 - 力扣(LeetCode)

思路:

层序遍历+找每层最大值,很简单了

class Solution {
public:
    vector<int> largestValues(TreeNode* root) {
        vector<int> ret;
        if(root==nullptr)return ret;
        queue<TreeNode*> q;
        q.push(root);
        while(q.size())
        {
            //应该开头更新maxnum!且数据有负数应该记为intmin
            int maxnum=INT_MIN;
            int sz=q.size();
            for(int i=0;i<sz;++i)
            {
                TreeNode*t=q.front();
                q.pop();
                maxnum=max(maxnum,t->val);
                if(t->left)q.push(t->left);
                if(t->right)q.push(t->right);
            }
            ret.push_back(maxnum);
        }
        return ret;
    }
};

此篇完。今天任务依旧很轻松呀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_dindong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值