1. 题目解析与核心思路
这道题目看似简单,实则暗藏玄机。题目要求我们计算二叉树的最大宽度,这里的"宽度"定义非常特殊:每一层的宽度是该层最左和最右非空节点之间的所有位置数,包括中间的null节点。这与我们常规理解的"节点数量"完全不同。
举个例子,假设某层只有最左和最右两个非空节点,中间有5个null节点,那么这层的宽度是7(2个非空+5个null)。这种定义使得我们不能简单地统计每层的节点数,而需要考虑节点的位置关系。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 暴力解法的问题分析
2.1 直观但不可行的思路
很多人的第一反应是:在层序遍历时,把所有节点(包括null)都放入队列,然后计算每层的宽度。这种方法理论上可行,但实际上存在严重问题:
-
存储空间爆炸:对于高度为h的树,最坏情况下需要存储2^h-1个节点。当h=15时,就需要存储32767个节点,远超题目给定的3000节点限制。
-
边界判定困难:难以区分哪些null节点应该计入宽度,哪些是超出边界的null节点。比如,某层最右非空节点之后的所有null节点不应计入宽度。
2.2 复杂度分析
假设树的高度为h:
- 时间复杂度:O(2^h),因为需要处理所有可能的节点位置
- 空间复杂度:O(2^h),需要存储所有节点
这种指数级复杂度显然无法满足题目要求。
3. 优化解法:索引标记法
3.1 核心思路
我们借鉴堆的数组表示法,给每个节点赋予一个索引编号:
- 根节点编号为1
- 左子节点编号为2×父节点编号
- 右子节点编号为2×父节点编号+1
这样,我们可以在不实际存储null节点的情况下,通过编号计算出每层的宽度。
3.2 算法步骤
- 使用队列进行层序遍历,队列元素为(节点指针, 节点编号)
- 初始化时将根节点(ptr, 1)入队
- 对于每一层:
- 记录该层首尾节点的编号
- 宽度 = 尾编号 - 首编号 + 1
- 更新最大宽度
- 将该层所有节点的子节点(带编号)入队
3.3 关键实现细节
cpp复制int widthOfBinaryTree(TreeNode* root) {
if(!root) return 0;
queue<pair<TreeNo
