1. 题目描述

给定一个二叉树,编写一个函数来获取这个树的最大宽度。树的宽度是所有层中的最大宽度。这个二叉树与满二叉树(full binary tree) 结构相同,但一些节点为空。

每一层的宽度被定义为两个端点(该层最左和最右的非空节点,两端点间的​​null​​​节点也计入长度)之间的长度。
示例 1:

输入:
1
/ \
3 2
/ \ \
5 3 9
输出: 4
解释: 最大值出现在树的第 3 层,宽度为 4 (5,3,null,9)

示例 2:

输入:
1
/
3
/ \
5 3
输出: 2
解释: 最大值出现在树的第 3 层,宽度为 2 (5,3)

示例 3:

输入:
1
/ \
3 2
/
5
输出: 2
解释: 最大值出现在树的第 2 层,宽度为 2 (3,2)

示例 4:

输入:
1
/ \
3 2
/ \
5 9
/ \
6 7
输出: 8
解释: 最大值出现在树的第 4 层,宽度为 8 (6,null,null,null,null,null,null,7)

注意: 答案在32位有符号整数的表示范围内。

2. 解题思路

这个题目,我们可以一层一层对二叉树进行遍历,初始化一个队列来保存这一层的节点,这个队列中保存着当前节点的节点值和索引值。

我们知道,一个节点的左子树的索引值是其索引值的两倍,即:​​left = index* 2​​​,右子树的索引值是其索引值的两倍加一,即:​​right = index * 2 + 1​​​。所以每层的宽度就是:​​right - left + 1​​,这样每一层的宽度值就求出来了,最大值也就自然而然的求出来了。

除此之外,我们还要考虑一种情况,就是二叉树深度特别深的时候,索引有可能就超出了数字的有效值。题目最后标明了:答案在32位有符号整数的表示范围内。也就是说最终答案那个最大宽度是不会超过32位有符号整数的。上面的想法是空节点也标注了索引,假如层数很多,但每层只有一个右节点的用例,空节点也计数就不行了,因为并没有限制层数。我们可以让同一层节点的索引先减去此层第一个节点的索引再来计算子节点的索引,这样每一层的索引都是从0开始的,从而解决数字大的问题。

复杂度分析:

  • 时间复杂度:O(n),其中n是二叉树的节点数,我们需要遍历完整个二叉树;
  • 空间复杂度:O(n),其中n是nodes栈的长度。

3. 代码实现

/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var widthOfBinaryTree = function(root) {
if(!root){
return 0
}

const nodes = [{node: root, index: 0}]
let res = 0

while(nodes.length){
let len = nodes.length
const start = nodes[0].index
const end = nodes[len - 1].index
res = Math.max(res, end - start + 1)

while(len--){
let {node, index} = nodes.shift()

index -= start

node.left && nodes.push({ node: node.left, index: index * 2 })
node.right && nodes.push({ node: node.right, index: index * 2 + 1 })
}
}
return res
};

4. 提交结果

2021-02-09 | 662. 二叉树最大宽度_数据结构