LeetCode探索(130):662-二叉树最大宽度

132 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第27天,点击查看活动详情 >>

题目

给你一棵二叉树的根节点 root ,返回树的 最大宽度

树的 最大宽度 是所有层中最大的 宽度

每一层的 宽度 被定义为该层最左和最右的非空节点(即,两个端点)之间的长度。将这个二叉树视作与满二叉树结构相同,两端点间会出现一些延伸到这一层的 null 节点,这些 null 节点也计入长度。

题目数据保证答案将会在 32 位 带符号整数范围内。

示例 1:

img

输入:root = [1,3,2,5,3,null,9]
输出:4
解释:最大宽度出现在树的第 3 层,宽度为 4 (5,3,null,9) 。

示例 2:

img

输入:root = [1,3,2,5,null,null,9,6,null,7]
输出:7
解释:最大宽度出现在树的第 4 层,宽度为 7 (6,null,null,null,null,null,7) 。

示例 3:

img

输入:root = [1,3,2,5]
输出:2
解释:最大宽度出现在树的第 2 层,宽度为 2 (3,2) 。

提示:

  • 树中节点的数目范围是 [1, 3000]
  • -100 <= Node.val <= 100

思考

本题难度中等。

首先是读懂题意。给你一棵二叉树的根节点 root ,返回树的最大宽度。这里的最大宽度,是指二叉树的所有层中最左和最右两个节点之间的宽度,包括了空节点。需要注意的是,如果二叉树是 [1,3,2,5],最大宽度只有2,因为第三层只有一个节点,其他都是空节点不包括,因此这一层的宽度为1。

我们可以使用广度优先搜索方法进行解题。定义类 AnnotatedNode 存储节点、节点层数和节点位置。定义 left 为一层中最左的节点的位置,对于每一个深度,第一个遇到的节点是最左边的节点,此时更新 left。遍历同一层的所有节点,宽度为pos - left + 1,最大宽度取这些值中的最大值。

在JS中最大安全整数是2^53 - 1,考虑到测试用例中的特殊情况,当采用满二叉树的方式为每个节点做计数标记时,一不小心就会溢出。因此这里使用 BigInt 来计数。

解答

方法一:广度优先搜索

/**
 * @param {TreeNode} root
 * @return {number}
 */
var widthOfBinaryTree = function(root) {
  let queue = []
  queue.push(new AnnotatedNode(root, 0, 0n))
  let curDepth = 0, left = 0n, ans = 0n
  while (queue.length) {
    // 取出数组的第一个元素
    let a = queue.shift()
    if (a.node != null) {
      queue.push(new AnnotatedNode(a.node.left, a.depth + 1, a.pos * 2n))
      queue.push(new AnnotatedNode(a.node.right, a.depth + 1, a.pos * 2n + 1n))
      // 对于每一个深度,第一个遇到的节点是最左边的节点,此时更新left
      if (curDepth !== a.depth) {
        curDepth = a.depth
        left = a.pos
      }
      if (a.pos - left + 1n > ans) {
        ans = a.pos - left + 1n
      }
    }
  }
  return ans
}
class AnnotatedNode {
  constructor (node, depth, pos) {
    this.node = node
    this.depth = depth
    this.pos = pos
  }
}

复杂度分析:

  • 时间复杂度:O(n),其中 n 为二叉树的节点数目,我们遍历每个节点一遍。
  • 空间复杂度:O(n)。

参考