leetcode
leetcode 701 ~ 750
二叉树剪枝

二叉树剪枝

难度:

标签:

题目描述

给你二叉树的根结点 root ,此外树的每个结点的值要么是 0 ,要么是 1

返回移除了所有不包含 1 的子树的原二叉树。

节点 node 的子树为 node 本身加上所有 node 的后代。

 

示例 1:

输入:root = [1,null,0,0,1]
输出:[1,null,0,null,1]
解释:
只有红色节点满足条件“所有不包含 1 的子树”。 右图为返回的答案。

示例 2:

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

示例 3:

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

 

提示:

  • 树中节点的数目在范围 [1, 200]
  • Node.val01

代码结果

运行时间: 24 ms, 内存: 0.0 MB


/*
 * 思路:
 * 1. 使用 Java 8 Stream API 解决此问题。
 * 2. 定义一个辅助方法 pruneTree,用于递归修剪树。
 * 3. 在辅助方法中,递归处理左右子树。
 * 4. 使用 Optional 类来处理节点的存在性。
 */
 
import java.util.Optional;
 
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}
 
public class Solution {
    public TreeNode pruneTree(TreeNode root) {
        return Optional.ofNullable(root)
                       .map(node -> {
                           node.left = pruneTree(node.left);
                           node.right = pruneTree(node.right);
                           return (node.val == 0 && node.left == null && node.right == null) ? null : node;
                       })
                       .orElse(null);
    }
}

解释

方法:

这个解法使用了后序遍历的方式来剪枝二叉树。从叶子节点开始递归,如果一个节点的左右子树都被剪枝了,并且当前节点的值为0,那么当前节点也需要被剪枝。通过后序遍历,可以保证每个节点的子树都已经被正确剪枝后,再来判断当前节点是否需要剪枝。最后,如果整棵树都被剪枝了,就返回None,否则返回根节点。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
后序遍历为何是剪枝二叉树的合适选择?
后序遍历是剪枝二叉树的合适选择,因为它允许我们先处理节点的子节点,再处理节点本身。这种方式确保在我们决定是否剪除当前节点之前,其子树已经被适当地处理和剪枝。这样,我们可以根据子节点的剪枝结果来决定当前节点是否也需要被剪枝。如果从上到下进行剪枝,我们可能会遇到需要重新考虑先前决策的情况,因为父节点的剪枝状态可能依赖于其子节点的状态。
🦆
在判断是否剪枝当前节点时,为什么即使左右子树都被剪枝,只要当前节点值为1,就不剪枝这个节点?
在决定是否剪枝当前节点时,如果节点的值为1,则该节点应保留,因为它对应的是有效或重要的数据(例如在某些问题中,1可能代表特定的有效状态或特征)。即使其左右子树都被剪枝(即子节点都不重要或都是0),只要当前节点的值为1,它本身就足以保留。剪枝的目的是去除那些不影响最终结果的部分(例如值为0的无效部分),而不是去除所有非叶子节点。
🦆
如果根节点的值为0且其左右子树也全被剪枝,这种情况下根节点是否被剪除,函数是否正确处理这种情况?
是的,如果根节点的值为0且其左右子树也都被剪枝,根据提供的函数逻辑,这个根节点也会被剪除。函数中有一个检查过程,如果`subTreeFix`返回False,表示整棵树都可以被剪枝。在这种情况下,根节点也不会被保留,函数将返回None。这表明函数正确处理了这种情况,符合剪枝的预期目的。
🦆
递归函数`subTreeFix`为什么在节点为None时返回False,这代表了什么意义?
在递归函数`subTreeFix`中,当遇到一个None的节点时返回False,这表示该节点(或其位置)不包含任何需要保留的值或结构,即它为空或者无效。返回False在逻辑上代表此位置的子树不包含任何有效的或需要保留的数据,因此不会对父节点的剪枝决策产生影响(即父节点的剪枝决策不会因为一个不存在的子节点而改变)。这有助于简化剪枝的决策过程,只关注存在且可能包含有效数据的节点。

相关问题