一、【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