给定一个二叉树,编写一个函数来获取这个树的最大宽度。树的宽度是所有层中的最大宽度。这个二叉树与**满二叉树(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位有符号整数的表示范围内。
BFS广度优先遍历
广度优先是先遍历每一层的所有结点,记录宽度,再向下一层遍历。根据满二叉树的性质,假定当前节点在数组中的下标为i,那么其左子节点的下标为2i,其右子结点的下标为2i+1,所以,记录当前层的最左节点的下标,再用当前节点的下标想减再+1,便可得到当前层的宽度。然后与记录值ans进行比较,再进行下层遍历。
var widthOfBinaryTree = function (root) {
let q = [];
let ans = 0
q.push([root, 0]);
while (q.length > 0) {
let len = q.length;
let l = q[0][1], r = q[0][1];
for (let i = 0; i < len; i++) {
item = q[0];
r = item[1]
if (item[0].left) {
q.push([item[0].left, r * 2])
}
if (item[0].right) {
q.push([item[0].right, r * 2 + 1])
}
q.shift()
}
ans = Math.max(ans, r - l + 1)
}
return ans
};
但是这种情况下,当数据过大的时候会出现栈溢出,导致最后的结果出现NAN,所以我们需要进行数据优化,我们将 q.push([item[0].left, r * 2])中的r改为(r-l),通过改变下标数的量级,防止溢栈。
var widthOfBinaryTree = function (root) {
let q = [];
let ans = 0
q.push([root, 0]);
while (q.length > 0) {
let len = q.length;
let l = q[0][1], r = q[0][1];
for (let i = 0; i < len; i++) {
item = q[0];
r = item[1]
if (item[0].left) {
q.push([item[0].left, (r - l) * 2])
}
if (item[0].right) {
q.push([item[0].right, (r - l) * 2 + 1])
}
q.shift()
}
ans = Math.max(ans, r - l + 1)
}
return ans
};
DFS深度优先
深度优先则是每次都将该节点的所有子节点遍历完成,记录每个节点的深度,并记录当前深度的结点值,如果当前节点没有被记录过,则记录当前深度的最左节点下标,如果当前深度记录过,则用当前节点的下标与当前节点的首下标进行想减,取当前深度的节点数。
var widthOfBinaryTree = function (root) {
let ans = 0;
let left = new Map();
dfs(root, 0, 0);
return ans;
function dfs(root, depth, pos) {
if (!root) return;
if (!left.has(depth)) left.set(depth, pos);
ans = Math.max(ans, pos - left.get(depth) + 1);
dfs(root.left, depth + 1, 2 * (pos - left.get(depth)));
dfs(root.right, depth + 1, (pos - left.get(depth)) * 2 + 1)
}
};