关于我以为我会广度优先遍历了

100 阅读3分钟

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;
}

四、总结:

写出能运行的代码不难,难得是写出运行快的代码呀