1. 理解题目与问题拆解
第一次看到力扣662题"二叉树最大宽度"时,我下意识以为是要计算最宽的那层节点数量。但仔细阅读题目描述才发现,这里的"宽度"定义需要精确到每个节点在完全二叉树中的位置编号。这种对传统BFS的改造需求,正是这道题的巧妙之处。
题目要求我们计算二叉树所有层中的最大宽度,其中宽度的定义是某一层最左和最右非空节点之间的跨度(包括中间的null节点)。举个例子,对于这样一棵树:
code复制 1
/ \
3 2
/ \ \
5 3 9
第三层的宽度是4(5到9之间跨越了4个位置),而不是简单的节点数3。这种计算方式实际上是在模拟完全二叉树的编号体系。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心思路与算法选择
2.1 为什么选择BFS而非DFS
在树结构问题中,DFS和BFS都是常见选择。但本题需要按层计算宽度,BFS天然适合处理这种层级信息。使用BFS可以:
- 自然地按层遍历节点
- 在遍历每层时记录节点位置
- 实时计算当前层的宽度
相比之下,DFS虽然也能通过记录深度信息实现分层,但代码会复杂许多,尤其在处理位置编号时容易出错。
2.2 位置编号的数学原理
这是本题的关键创新点。我们给每个节点赋予一个位置编号:
- 根节点为1
- 左子节点为 parent_pos * 2
- 右子节点为 parent_pos * 2 + 1
这种编号方式源自完全二叉树的特性。通过这种编号,我们可以精确计算任意两个节点之间的跨度,即使中间节点不存在也能正确表示。
注意:直接使用这种编号可能导致大数问题(当树很深时编号会非常大)。但在力扣的测试用例范围内,使用unsigned long long足够应对。
3. 完整实现与代码解析
3.1 数据结构设计
我们使用标准队列进行BFS,但队列元素需要同时存储节点指针和位置编号:
cpp复制struct QueueNode {
TreeNode* node;
unsigned long long pos;
};
3.2 算法主框架
cpp复制int widthOfBinaryTree(TreeNode* root) {
if (!root) r
