《算法题讲解指南:优选算法-队列+宽搜》--70.N叉树的层序遍历,71.二叉树的锯齿形层序遍历,72.二叉树的最大宽度,73.在每个树行中找最大值

🔥小叶-duck个人主页

❄️个人专栏《Data-Structure-Learning》《C++入门到进阶&自我学习过程记录》
《算法题讲解指南》--优选算法
《算法题讲解指南》--递归、搜索与回溯算法
《算法题讲解指南》--动态规划算法

未择之路,不须回头
已择之路,纵是荆棘遍野,亦作花海遨游


目录

70.N叉树的层序遍历

题目链接:

题目描述:

题目示例:

解法:

算法思路:

C++算法代码:

算法总结及流程解析:

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

题目链接:

题目描述:

题目示例:

解法(层序遍历):

算法思路:

C++算法代码:

算法总结及流程解析:

72.二叉树的最大宽度

题目链接:

题目描述:

题目示例:

解法(层序遍历):

算法思路:

C++算法代码:

算法总结及流程解析:

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

题目链接:

题目描述:

题目示例:

解法(bfs):

算法思路:

结束语


70.N叉树的层序遍历

题目链接:

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

题目描述:

题目示例:

解法:

算法思路:

层序遍历即可

仅需多加一个变量,用来记录每一层结点的个数就好了。

C++算法代码:

cpp 复制代码
class Solution {
public:
    vector<vector<int>> levelOrder(Node* root) 
    {
        vector<vector<int>> ret;
        queue<Node*> q;
        if(root)
        {
            q.push(root);
        }
        while(q.size())
        {
            vector<int> tmp;
            int sz = q.size();
            while(sz--)
            {
                Node* node = q.front();
                tmp.push_back(node->val);
                for(auto e : node->children)
                {
                    if(e)
                    {
                        q.push(e);
                    }
                }
                q.pop();
            }
            ret.push_back(tmp);
        }
        return ret;
    }
};

算法总结及流程解析:

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

题目链接:

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

题目描述:

题目示例:

解法(层序遍历):

算法思路:

在正常的层序遍历过程中,我们是可以把一层的结点放在一个数组中去的。

既然我们有这个数组,在合适的层数逆序就可以得到锯齿形层序遍历的结果。

C++算法代码:

cpp 复制代码
class Solution {
public:
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) 
    {
        vector<vector<int>> ret;
        queue<TreeNode*> q;
        int flag = 0;
        if(root)
        {
            q.push(root);
        }
        while(q.size())
        {
            int sz = q.size();
            vector<int> tmp;
            while(sz--)
            {
                TreeNode* node = q.front();
                tmp.push_back(node->val);
                if(node->left)
                {
                    q.push(node->left);
                }
                if(node->right)
                {
                    q.push(node->right);
                }
                q.pop();
            }
            if(flag == 0)
            {
                flag = 1;
            }
            else
            {
                reverse(tmp.begin(), tmp.end());
                flag = 0;
            }
            ret.push_back(tmp);
        }
        return ret;
    }
};

算法总结及流程解析:

72.二叉树的最大宽度

题目链接:

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

题目描述:

题目示例:

解法(层序遍历):

算法思路:

1.第一种思路(会超过内存限制):

既然统计每一层的最大宽度,我们优先想到的就是利用层序遍历,把当前层的结点全部存在队列里面,利用队列的长度来计算每一层的宽度,统计出最大的宽度。

但是,由于空节点也是需要计算在内的。因此,我们可以选择将空节点也存在队列里面。

这个思路是我们正常会想到的思路,但是极端境况下,最左边一条长链,最右边一条长链,我们需要存几亿个空节点,会超过最大内存限制。

2.第二种思路(利用二叉树的顺序存储 -通过根节点的下标,计算左右孩子的下标):

依旧是利用层序遍历,但是这一次队列里面不单单存结点信息,并且还存储当前结点如果在数组中存储所对应的下标(在我们学习数据结构-堆的时候,计算左右孩子的方式)。

这样我们计算每一层宽度的时候,无需考虑空节点,只需将当层结点的左右结点的下标相减再加1即可。

但是,这里有个细节问题:如果二叉树的层数非常恐怖的话,我们任何一种数据类型都不能存下下标的值。但是没有问题,因为

我们数据的存储一个环形的结构

并且题目说明,数据的范围在int这个类型的最大值的范围之内,因此不会超出一圈;

因此,如果是求差值 的话,我们无需考虑溢出的情况

C++算法代码:

cpp 复制代码
class Solution {
public:
    int widthOfBinaryTree(TreeNode* root) 
    {
        //利用二叉树堆的底层结构数组这个特性,将结点和对应下标进行绑定
        //这样就可以快速计算一层中任意两个结点之间的距离(下标之差)
        queue<pair<TreeNode*, unsigned int>> q;
        q.push({root, 1});
        unsigned int len = 0;
        while(q.size())
        {
            //在放入下一层数据之前将当前层的宽度进行计算并且将最大宽度进行更新
            unsigned int Left = q.front().second;
            unsigned int Right = q.back().second;
            len = max(len, Right - Left + 1);
            //让下一层数据进队列
            int sz = q.size();
            while(sz--)
            {
                if(q.front().first->left)
                {
                    //进队前判断结点左孩子是否为空
                    q.push({q.front().first->left, q.front().second * 2});
                }
                if(q.front().first->right)
                {
                    //进队前判断结点右孩子是否为空
                    q.push({q.front().first->right, q.front().second * 2 + 1});
                }
                q.pop();
            }
        }
        return len;
    }
};

算法总结及流程解析:

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

题目链接:

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

题目描述:

题目示例:

解法(bfs):

算法思路:

层序遍历过程中,在执行让下一层节点入队的时候,我们是可以在循环中统计出当前层结点的最大值的。

因此,可以在 bfs 的过程中,统计出每一层结点的最大值。

cpp 复制代码
class Solution {
public:
    vector<int> largestValues(TreeNode* root) 
    {
        vector<int> ret;
        queue<TreeNode*> q;
        if(root)
        {
            q.push(root);
        }    
        while(q.size())
        {
            int sz = q.size();
            int len = INT_MIN;
            while(sz--)
            {
                len = max(len, q.front()->val);
                if(q.front()->left)
                {
                    q.push(q.front()->left);
                }
                if(q.front()->right)
                {
                    q.push(q.front()->right);
                }
                q.pop();
            }
            ret.push_back(len);
        }
        return ret;
    }
};

结束语

70.N叉树的层序遍历,71.二叉树的锯齿形层序遍历,72.二叉树的最大宽度,73.在每个树行中找最大值 这四道算法题就讲解完了。**N叉树层序遍历:通过队列记录每层节点数;二叉树锯齿形遍历:在层序遍历基础上适时反转数组; 二叉树最大宽度:采用节点下标差值法避免内存溢出;每层寻找最大值:通过层序遍历过程中比较节点值。**希望大家能有所收获!

相关推荐
代码改善世界2 小时前
【C++初阶】双向循环链表:List底层结构的完整实现剖析
c++·链表·list
汀、人工智能2 小时前
[特殊字符] 第98课:数据流中位数
数据结构·算法·数据库架构··数据流·数据流中位数
REDcker2 小时前
C++ 包管理工具概览
开发语言·c++
Eloudy2 小时前
不同特征值的特征向量互相正交的矩阵
人工智能·算法·机器学习
人道领域2 小时前
【LeetCode刷题日记】:从 LeetCode 经典题看哈希表的场景化应用---数组、HashSet、HashMap 选型与算法实战
算法·leetcode·面试
努力努力再努力wz2 小时前
【C++高阶系列】告别内查找局限:基于磁盘 I/O 视角的 B 树深度剖析与 C++ 泛型实现!(附B树实现源码)
java·linux·开发语言·数据结构·c++·b树·算法
承渊政道2 小时前
【优选算法】(实战攻坚BFS之FloodFill、最短路径问题、多源BFS以及解决拓扑排序)
数据结构·c++·笔记·学习·算法·leetcode·宽度优先
kishu_iOS&AI2 小时前
机器学习 —— 线性回归(2)
人工智能·python·算法·机器学习·线性回归
NULL指向我2 小时前
信号处理学习笔记6:ADC采样线性处理实测拟合
人工智能·算法·机器学习