[前端]_一起刷leetcode 662. 二叉树最大宽度

501 阅读4分钟

大家好,我是挨打的阿木木,爱好算法的前端摸鱼老。最近会频繁给大家分享我刷算法题过程中的思路和心得。如果你也是想提高逼格的摸鱼老,欢迎关注我,一起学习。

题目

662. 二叉树最大宽度

给定一个二叉树,编写一个函数来获取这个树的最大宽度。树的宽度是所有层中的最大宽度。这个二叉树与满二叉树(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位有符号整数的表示范围内。

思路

  1. 这道题目的意思给大家翻译一下就是,每一层的所有节点,前后都可以去除Null的部分,直到有值为止,然后判断有效部分的最大长度;
  2. 那么照这个思路,我第一个想到的是用一个数组把每一轮的值都存起来,然后再用一个方法去去除左右的空位,这样子每一轮得到的值进行长度的判断,取上一轮的最大长度和当前长度的最大值。

暴力解法

/**
 * 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) {
    let maxCount = 0;

    // 记录上一轮的列表数据
    let prevArr = [ root ];

    while (filterRightNullData(prevArr).length) {
        maxCount = Math.max(maxCount, filterRightNullData(prevArr).length);

        prevArr = prevArr.reduce((total, cur) => {
            total.push(cur && cur.left);
            total.push(cur && cur.right);

            return total;
        }, []);
    }

    return maxCount;
    
};

// 删除两边的Null元素
function filterRightNullData(arr) {
    while (arr.length && arr[0] === null) {
        arr.shift();
    }

    while (arr.length && arr[arr.length - 1] === null) {
        arr.pop();
    }

    return arr;
}

翻车现场

image.png

事实告诉我,暴力解法不可取,内存空间溢出了,所以我们需要找规律。我又想到我们没必要每一轮把Null节点也统计进去,我们大可以只统计有效的节点,同时我们需要给有效的节点添加一个坐标值,记录一下它是第几个,这样子把左右有效节点的坐标值相减一样可以达到我们要的效果。

再次翻车代码

/**
 * 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 prevArr = [ { node: root, index: 0 } ];
    // 记录最大长度
    let maxCount = 1;

    while (prevArr.length) {
        // 超过两个节点才可以判断索引差, 记得差和数量之间需要 + 1
        if (prevArr.length > 1) {
            let curCount = prevArr[prevArr.length - 1].index - prevArr[0].index + 1;
            maxCount = Math.max(maxCount, curCount);
        }

        prevArr = prevArr.reduce((total, cur) => {
            // 非空节点才进行存储
            // 索引关系, 左节点等于2n,右节点等于2n + 1
            cur.node.left && total.push({ node: cur.node.left, index: cur.index * 2 });
            cur.node.right && total.push({ node: cur.node.right, index: cur.index * 2 + 1 });

            return total;
        }, []);
    }

    return maxCount;
    
};

事故现场

image.png

原因

image.png

由于题目中说了,答案在32位有符号整数的表示范围内,这意味着结果可能特别大,我们用普通的number可能无法去存储这么大的数字, 所以我们要对大数进行一个取余操作。

最终代码

/**
 * 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 prevArr = [ { node: root, index: 0 } ];
    // 记录最大长度
    let maxCount = 1;
    // 数字可能过大,会溢出,所以我们要进行取余操作
    let mod = Math.pow(2, 32);

    while (prevArr.length) {
        // 超过两个节点才可以判断索引差, 记得差和数量之间需要 + 1
        if (prevArr.length > 1) {
            let curCount = prevArr[prevArr.length - 1].index - prevArr[0].index + 1;
            maxCount = Math.max(maxCount, curCount);
        }

        prevArr = prevArr.reduce((total, cur) => {
            // 非空节点才进行存储
            // 索引关系, 左节点等于2n,右节点等于2n + 1, 数字可能过大需要取余
            const curIndex = cur.index * 2 % mod;
            cur.node.left && total.push({ node: cur.node.left, index: curIndex });
            cur.node.right && total.push({ node: cur.node.right, index: curIndex + 1 });

            return total;
        }, []);
    }

    return maxCount;
    
};

看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。