二叉树最大宽度
给定一个二叉树,编写一个函数来获取这个树的最大宽度。树的宽度是所有层中的最大宽度。这个二叉树与满二叉树(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位有符号整数的表示范围内。
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/ma… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
给每一行的节点附上编号(参考完全二叉树:父树编号i,左子树编号就是2i,右子树编号就是2i+1)
例如:
a
/ \
b c
树a编号赋值:0
树a的左子树b编号就是:2i = 2*0 = 0
树a的右子树c编号就是:2i + 1 = 2*0 + 1 = 1
得出树a的两个子树的编号,相减再+1 = 2
得出此树最大宽度为2
所以这道题的解题思路就是:给每一行都附加一个编号,该行最大的差值就是这该行的最大宽度
代码
var widthOfBinaryTree = function (root) {
// 当树为空,直接返回0
if (!root) return 0;
// 树不为空,根节点的宽度为1,附加一个起始编号0
let max = 1, que = [[0, root]];
// while循环作用:遍历当前que数组(当前行),取当前行的最大宽度,以及取当前行的左右子树
while (que.length) {
// 计算宽度
let width = que[que.length - 1][0] - que[0][0] + 1;
// 取宽度最大值,赋给max
max = Math.max(max, width);
// temp作用:保存当前行的所有左右子树,用于下次循环
let temp = [];
for (const [i, q] of que) {
// 左子树的编号是该行编号*2
q.left && temp.push([i * 2, q.left]);
// 右子树的编号是该行编号*2 +1
q.right && temp.push([i * 2 + 1, q.right]);
}
// temp记录完该行所有的左右子树后,赋给que,用于下次循环
que = temp;
}
return max;
};
但是当树特别长的时候,附加的编号会特别大,所以我们可以在计算编号时,使用父节点的编号i前,先让父节点的编号i减去父节点该行的最小编号
如下图
修改后的代码如下
var widthOfBinaryTree = function (root) {
// 当树为空,直接返回0
if (!root) return 0;
// 树不为空,根节点的宽度为1,附加一个起始编号0
let max = 1, que = [[0, root]];
// while循环作用:遍历当前que数组(当前行),取当前行的最大宽度,以及取当前行的左右子树
while (que.length) {
// 计算宽度
let width = que[que.length - 1][0] - que[0][0] + 1;
// 取宽度最大值,赋给max
max = Math.max(max, width);
// temp作用:保存当前行的所有左右子树,用于下次循环
let temp = [];
for (const [i, q] of que) {
// 左子树的编号是该行编号*2
q.left && temp.push([(i - que[0][0] + 1) * 2, q.left]);
// 右子树的编号是该行编号*2 +1
q.right && temp.push([(i - que[0][0] + 1) * 2 + 1, q.right]);
}
// temp记录完该行所有的左右子树后,赋给que,用于下次循环
que = temp;
}
return max;
};