在问 · 算法题解

814. 二叉树剪枝

题目描述

输入二叉树的根节点 root,每个节点的值只会是 0 或 1。树用层序数组表示,空位记为 null。

一个节点的子树包括这个节点本身和它的全部后代。把所有不含值为 1 的节点的子树从树上删掉。

返回剪完之后的树的根。如果整棵树都不含 1,返回空树。

示例 1
输入:root = [1,null,0,0,1]
输出:[1,null,0,null,1]

解释:根的右孩子 0 下面挂着的左孩子 0 不含 1,被剪掉;右孩子 0 因为下面有 1 而保留。

示例 2
输入:root = [1,0,1,0,0,0,1]
输出:[1,null,1,null,1]

解释:所有只含 0 的子树都被剪掉,只剩一条全是 1 的右链。

示例 3
输入:root = [1,1,0,1,1,0,1,0]
输出:[1,1,0,1,1,null,1]

解释:两个值为 0 的叶子被剪掉;根的右孩子 0 因为下面有 1 而保留。

数据范围

  • 节点数在 [1, 200] 范围内。
  • Node.val 只会是 0 或 1。

解题思路

一个子树要不要剪,取决于它的子树剪完之后还剩什么,所以用后序遍历:先递归剪左右子树,再看当前节点。若当前值为 0 且左右都已被剪空,说明整个子树不含 1,返回 None 让父节点把它摘掉;否则保留。

为什么正确

pruneTree(x) 返回后,以 x 为根的子树中每个剩余子树都至少含一个 1。

复杂度分析

时间 O(n),每个节点访问一次;空间 O(h),h 为树高(递归栈)。

易错点

先判断当前节点再递归(先序)是错的:一个 0 节点在剪掉孩子之前看起来有孩子,剪完后却可能变成要删的叶子。必须先剪子树。

参考代码

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

class Solution:
    def pruneTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if root is None:
            return None
        root.left = self.pruneTree(root.left)
        root.right = self.pruneTree(root.right)
        if root.val == 0 and root.left is None and root.right is None:
            return None
        return root

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

二叉树 专题的其他题目

查看 二叉树 全部题目 →