在问 · 算法题解

662. 二叉树最大宽度

中等二叉树广度优先搜索 + 位置编号力扣原题 ↗

题目描述

输入一棵二叉树的根节点 root,用层序数组表示,null 表示空位。

把这棵树想象成按满二叉树的位置排布。对每一层,取最左边和最右边的非空节点作为两端,两端之间所有的位置(包括其中本该在满二叉树里但实际为空的位置)都计入这一层的宽度。

返回所有层中宽度的最大值。题目保证答案在 32 位有符号整数范围内。

示例 1
输入:root = [1,3,2,5,3,null,9]
输出:4

解释:第 3 层从 5 到 9 共占 4 个位置。

示例 2
输入:root = [1,3,2,5,null,null,9,6,null,7]
输出:7

解释:第 4 层两端是 6 和 7,中间有 5 个空位,宽度为 7。

示例 3
输入:root = [1,3,2,5]
输出:2

解释:第 2 层的 3 和 2 宽度为 2。

数据范围

  • 节点数在 [1, 3000] 范围内。
  • -100 <= Node.val <= 100

解题思路:广度优先搜索 + 位置编号

给节点编号:父节点编号为 p,左孩子 2p,右孩子 2p+1(和堆的数组下标一样)。按层 BFS,每层宽度 = 最右编号 - 最左编号 + 1。树很深时编号会指数增长,所以每层先把编号减去本层最左编号(归一化),再生成下一层编号,就不会溢出。

为什么正确

同一层内两个节点的编号差等于它们在满二叉树中的位置差;对整层编号同时减去一个常数不改变这个差。

复杂度分析

时间 O(n),空间 O(n)(最宽一层的节点数)。

易错点

不能只数每层的非空节点个数,中间的空位也算宽度。另外,一条 3000 层的单链会让编号达到 2^3000,在 C++/Java/Go/JS 中必溢出,必须每层归一化。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def widthOfBinaryTree(self, root: Optional[TreeNode]) -> int:
        ans = 0
        level = [(root, 0)]
        while level:
            first = level[0][1]
            ans = max(ans, level[-1][1] - first + 1)
            nxt = []
            for node, pos in level:
                p = pos - first
                if node.left:
                    nxt.append((node.left, 2 * p))
                if node.right:
                    nxt.append((node.right, 2 * p + 1))
            level = nxt
        return ans

载入编辑器,自己跑一遍 →

其他解法

两种解法的编号方式相同,只是求每层最左、最右编号的方式不同:广度优先搜索直接按层取首尾,深度优先搜索靠先左后右的顺序记下每层最左编号。

解法 2:深度优先搜索 + 位置编号 时间 O(n),空间 O(n)

仍然按完全二叉树编号:左孩子是 2·pos,右孩子是 2·pos + 1。先左后右地深度优先搜索,每一层第一次到达的节点就是该层最左节点,用 first[depth] 记下它的编号。之后该层每个节点的宽度是 pos − first[depth] + 1,取最大值。为防编号溢出,向下传递时先减去 first[depth],只保留相对编号。

不需要队列保存整层节点,空间取决于树高。代价是要依赖“先左后右”的遍历顺序才能得到每层最左节点,树很深时递归栈也会很深。

class Solution:
    def widthOfBinaryTree(self, root: Optional[TreeNode]) -> int:
        first = []
        ans = 0

        def dfs(node, depth, pos):
            nonlocal ans
            if not node:
                return
            if depth == len(first):
                first.append(pos)
            p = pos - first[depth]
            ans = max(ans, p + 1)
            dfs(node.left, depth + 1, 2 * p)
            dfs(node.right, depth + 1, 2 * p + 1)

        dfs(root, 0, 0)
        return ans

二叉树 专题的其他题目

查看 二叉树 全部题目 →