《LeetCode 662 二叉树最大宽度 队列宽搜BFS解法》

一.题目

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

二.思路讲解

2.1 思路讲解

本题要求计算二叉树的最大宽度 ,即每一层最左非空节点到最右非空节点之间的长度(包括中间的空节点)。

如果能够为每个节点分配一个唯一的位置编号 ,那么同层最右节点的编号减去最左节点的编号再加 1 就是该层的宽度。

这种编号方式可以借鉴堆的数组存储思想 :假设根节点编号为 1 ,则左子节点编号为 2×父节点编号 ,右子节点编号为 2×父节点编号+1。这样,我们只需在层序遍历时,为每个节点记录其编号,并跟踪每层的最小和最大编号,即可计算宽度。

三.代码演示

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
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->left != nullptr) tmp.push_back({x->left,y * 2});
                if(x->right != nullptr) tmp.push_back({x->right,y * 2 + 1});
            }
            q = tmp;//更新数组
        }    
        return ret;
    }
};

四.代码讲解

一、数据结构与初始化
  • q :使用 vector<pair<TreeNode*, unsigned int>> 模拟队列,存储当前层的节点及其位置编号。根节点编号为 1

  • ret :记录当前遇到的最大宽度,初始为 0

二、主循环:逐层处理

q 非空时,表示还有节点未处理,继续循环。

1. 计算当前层宽度

  • 取出当前层队列的第一个节点 (即最左节点)的编号 y1

  • 取出当前层队列的最后一个节点 (即最右节点)的编号 y2

  • 当前层宽度为 y2 - y1 + 1,更新全局最大值 ret

2. 生成下一层节点

创建一个临时数组 tmp,用于存放下一层的节点及其编号。

  • 遍历当前层队列的每个节点 (x, y)

    • 如果左子节点存在,则将其编号设为 y * 2,并加入 tmp

    • 如果右子节点存在,则将其编号设为 y * 2 + 1,并加入 tmp

  • q 更新为 tmp,即进入下一层。

三、关键细节
  • 编号规则 :根节点编号为 1,左子节点编号为 2*父节点编号,右子节点编号为 2*父节点编号+1。这与堆的数组存储一致,能够准确反映节点的相对位置。

五、流程图