二叉树的修剪问题

一、【LeetCode 814】二叉树剪枝

1. 题目描述

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

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

( 节点 X 的子树为 X 本身,以及所有 X 的后代。)

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

在这里插入图片描述
解释:
只有红色节点满足条件“所有不包含 1 的子树”。
右图为返回的答案。

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

在这里插入图片描述

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

在这里插入图片描述

说明:

给定的二叉树最多有 100 个节点。
每个节点的值只会为 0 或 1 。

2. 踩的大坑(出来了还没意识到问题在哪)

一开始只想到了递归,没有考虑顺序,提交了之后就出现了如下的错误:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def pruneTree(self, root: TreeNode) -> TreeNode:
        if not root:
            return None
        if not root.left and not root.right and root.val == 0:
            root = None
        if root:
            root.left = self.pruneTree(root.left)
            root.right = self.pruneTree(root.right)
        return root
输入:[1,0,1,0,0,0,1]
输出:[1,0,1,null,null,null,1]
预期:[1,null,1,null,1]

因此剪枝只能从叶子节点开始遍历,然后再遍历父节点,这样才能保证每次剪枝是逐层剪去无用的节点,到父节点的时候无用的节点都已经去掉,只需要判断当前节点和它的子节点是否为0就可以了。所以这和二叉树的遍历顺序有关系(此处应该是后序遍历,想想后序遍历的递归怎么写的,应该就能明白啦)

3. 第一种方法

上面的错误代码修改调整了第二个和第三个 if 的顺序就对啦!记住是后序遍历!!要倒着来!
注意:
第二个 if 里的 root.left 和第三个里的 root.left 要对应上,不能改成 left = self.pruneTree(root.left),否则会报错

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

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

4. 第二种方法

这就是递归的做法了:

我们可以使用递归来解决这个问题。我们用 containOne(node) 函数来判断以 node 为根的子树中是否包含 1,其不包含 1 当且仅当以 node 的左右孩子为根的子树均不包含 1,并且 node 节点本身的值也不为 1。

如果 node 的左右孩子为根的子树不包含 1,那我们就需要把对应的指针置为空。例如当 node 的左孩子为根的子树不包含 1 时,我们将 node.left 置为 null。

在递归结束之后,如果整颗二叉树都不包含 1,那么我们返回 null,否则我们返回原来的根节点。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def pruneTree(self, root: TreeNode) -> TreeNode:
        if not root:
            return None
        self.ContainOne(root)
        return root
        
    def ContainOne(self, node):
        if not node:
            return False
        left = self.ContainOne(node.left)
        right = self.ContainOne(node.right)
        if not left:
            node.left = None
        if not right:
            node.right = None
        return node.val == 1 or left or right

二、【LeetCode 1325】删除给定值的叶子节点

1. 题目描述

给你一棵以 root 为根的二叉树和一个整数 target ,请你删除所有值为 target 的 叶子节点 。

注意,一旦删除值为 target 的叶子节点,它的父节点就可能变成叶子节点;如果新叶子节点的值恰好也是 target ,那么这个节点也应该被删除。

也就是说,你需要重复此过程直到不能继续删除。

示例 1:
在这里插入图片描述

输入:root = [1,2,3,2,null,2,4], target = 2 
输出:[1,null,3,null,4]

解释:
上面左边的图中,绿色节点为叶子节点,且它们的值与 target 相同(同为 2 ),它们会被删除,得到中间的图。
有一个新的节点变成了叶子节点且它的值与 target 相同,所以将再次进行删除,从而得到最右边的图。

示例 2:
在这里插入图片描述

输入:root = [1,3,3,3,2], target = 3
输出:[1,3,null,null,2]

示例 3:
在这里插入图片描述

输入:root = [1,2,null,2,null,2], target = 2
输出:[1]

解释:每一步都删除一个绿色的叶子节点(值为 2)。

示例 4:

输入:root = [1,1,1], target = 1
输出:[]

示例 5:

输入:root = [1,2,3], target = 1
输出:[1,2,3]

提示:

1 <= target <= 1000
每一棵树最多有 3000 个节点。
每一个节点值的范围是 [1, 1000] 。

2. 解题思路

跟上一题第一种方法差不多的思路,删除给定的叶子节点还是从最后一层往上删。

3. 代码

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def removeLeafNodes(self, root: TreeNode, target: int) -> TreeNode:
        if not root:
            return None
        if root:
            root.left = self.removeLeafNodes(root.left, target)
            root.right = self.removeLeafNodes(root.right, target)
        if not root.left and not root.right and root.val == target:
            return None   # 此处为 root = None 也可
        return root

三、【LeetCode】修剪二叉搜索树

1. 题目描述

给定一个二叉搜索树,同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树,使得所有节点的值在[L, R]中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。

示例 1:

输入: 
    1
   / \
  0   2

  L = 1
  R = 2

输出: 
     1
      \
       2

示例 2:

输入: 
    3
   / \
  0   4
   \
    2
   /
  1

  L = 1
  R = 3

输出: 
      3
     / 
   2   
  /
 1

2. 解题思路

  • 若树不存在,直接返回None;
  • 若根节点的值大于右边界 R,说明根节点右边的全部都要剪掉直接忽略,直接递归修剪左子树即可;
  • 同理若根节点的值小于左边界 L,说明根节点左边的全部都要剪掉直接忽略,直接递归修剪右子树即可;
  • 若根节点处于范围之间,则左子树和右子树都要修剪;
  • 最后返回 root 即可。

3. 代码

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def trimBST(self, root: TreeNode, L: int, R: int) -> TreeNode:
        if not root:
            return None
        if root.val > R:
            root = self.trimBST(root.left, L, R)
        elif root.val < L:
            root = self.trimBST(root.right, L, R)
        else:
            root.left = self.trimBST(root.left, L, R)
            root.right = self.trimBST(root.right, L, R)
        return root
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值