Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
一、题目描述:
给定一个二叉树,编写一个函数来获取这个树的最大宽度。树的宽度是所有层中的最大宽度。这个二叉树与满二叉树(full binary tree)结构相同,但一些节点为空。
每一层的宽度被定义为两个端点(该层最左和最右的非空节点,两端点间的null节点也计入长度)之间的长度。
输入:
1
/ \
3 2
/ \ \
5 3 9
输出: 4
解释: 最大值出现在树的第 3 层,宽度为 4 (5,3,null,9)。
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/ma… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二、思路分析:
读完题目发现关键词就是树的层数的最大数量! 那不是用我们最喜欢的层次遍历就可以很快的解决,我们只要把每一层有多少个节点统计一下,最后做一个比较,那么就可以找到最大的宽度了,那这题不是简简单单,可是后来才发现这个题目中还要包含空节点,而且是一个完全二叉树,也就是说每一层的边界的null是不计入,那我们只要再获取每一层的时候用前后指针去除那些null的节点就可以,如果整一层都是null的话就停止继续往下找即可。说干就干,于是有代码一的超时代码。那超时的原因应该就是双指针每次多要扫描两边造成的。也就是说左右两边为null,那么它的子孙节点大可不必加入到运算之中。那么我只要确定他是边界的null我就不加入不就好了,但是实践告诉我这样依旧会超时,我们知道,采用满二叉树的方式为每一个节点计数的话,那么每增加一层,计数就会增加一倍。而在JS中最大安全整数是2的53次方减1.那么一旦这颗树的高度超过了53层,我们的计数就会溢出了。所以我们得想办法来优化我们的计数方法。
作者:linxiaodong 链接:leetcode-cn.com/problems/ma… 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
没有思路了,怎么办,拿去看评论区呀哈哈,可以发现我们在左右区间的重复计算耗费了大量的时间,所以导致我们的代码超时了。
三、AC 代码:
代码一:
/**
* 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;
let queue=[root];
let result=0;
while(queue.length!==0){
let len=queue.length;
if(len>result){
let cnt=len;
let node1 = len-1;
let node2 = 0;
while(queue[node1]===null){
node1--;
cnt--;
}
if(cnt===0){
break;
}
while(queue[node2]===null){
node2++;
cnt--;
}
if(cnt>result){
result=cnt;
}
}
for(let i=0;i<len;i++){
let tem = queue.shift();
tem&&queue.push(tem.left)||queue.push(null);
tem&&queue.push(tem.right)||queue.push(null);
}
}
return result
};
代码二:
/**
* 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) {
const queue = [[root, 0]];
let res = 0; // 全局维护最大值
let left = 0; // 记录当前层最左边节点的计数值
let right = 0; // 记录当前层最右边节点的计数值
while (queue.length) {
left = queue[0][1];
const len = queue.length;
for (let i = 0; i < len; i++) {
let [h, pos] = queue.shift();
right = pos;
if (h.left) queue.push([h.left, 2 * (pos - left)]); // 重点,优化掉左边不需要计数的部分
if (h.right) queue.push([h.right, 2 * (pos - left) + 1]);
}
res = Math.max(res, right - left + 1);
}
return res;
}
四、总结:
写出能运行的代码不难,难得是写出运行快的代码呀