669. 修剪二叉搜索树
文档讲解:代码随想录
代码链接:. - 力扣(LeetCode)
这道题目中删除的可能不只是一个节点
常见误区:
遇到一个不在区间范围内的节点,我们不能直接将其删除,因为其左右孩子可能是符合要求的。比如,如果节点值大于了区间的右端点,那么这个节点的左孩子中可能是有符合要求的节点的。如果如果节点值小于了区间的左端点,那么这个节点的右孩子中可能是有符合要求的节点的。因为这是一颗二叉搜索树,节点的右孩子的值大于节点的值,节点的左孩子的值小于节点的值
正确的思路:
如果遇到了一个节点的值小于左边界的值,那么这个节点的左孩子都可以被删除了;我们可以直接向右去递归遍历,去修剪该节点对应的右子树(因为右子树中的点不一定都是符合要求的),修剪的结果即是在根节点上修剪的结果
如果节点的值大于右边界了,那么这个节点的右孩子都可以被删除了。我们可以直接向左去递归遍历,去修剪该节点对应的左子树(因为左子树中的点不一定都是符合要求的),修剪的结果即是在根节点上修剪的结果
递归的三要素:
第一要素:明确这个函数想要干什么
传入一个节点和左右区间,返回修剪之后的二叉树的根节点
第二要素:寻找递归结束条件
如果传入的是空那么就return 空
如果传入的节点的值超出了区间的范围,那么就开始修剪,并且返回修剪后的根节点即可。根据上面的分析,决定我们向左递归修剪还是向右递归修剪
第三要素:找出函数的等价关系式
如果传入的节点在区间内,那么我们就要分别对左右子树进行修剪,并且将修建后的左右子树的根节点依然传回原来的根节点。
class Solution:def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:# 如果根节点为空,则返回空if not root:return None# 如果根节点的值大于high,说明整个右子树都不符合条件,因此只需要修剪左子树if root.val > high:node = self.trimBST(root.left, low, high)return node# 如果根节点的值小于low,说明整个左子树都不符合条件,因此只需要修剪右子树if root.val < low:node = self.trimBST(root.right, low, high)return node# 修剪左子树和右子树,并更新根节点的左右子树root.left = self.trimBST(root.left, low, high)root.right = self.trimBST(root.right, low, high)return root
108.将有序数组转换为二叉搜索树
文档讲解:代码随想录
代码链接:. - 力扣(LeetCode)
将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
题目中强调的是高度平衡,为什么强调要平衡呢?因为只要给我们一个有序数组,如果不强调平衡,都可以以线性结构来构造二叉搜索树
构造二叉树的本质:寻找分割点,分割点作为当前节点,然后递归左区间和右区间。
本题问题:如果数组长度为偶数,中间节点有两个,取哪一个?
答案:取哪一个都可以,只不过构成了不同的平衡二叉搜索树。
如果要分割的数组长度为偶数的时候,中间元素为两个。这也是题目中强调答案不是唯一的原因
第一要素:明确这个函数想要干什么
传入一个数组,返回根据这个数组构造的平衡二叉树的根节点
第二要素:寻找递归结束条件
如果传入传入的数组的长度为1,那么就return 这一个节点
第三要素:找出函数的等价关系式
如果传入的数组的长度不为1,那么就要找到根节点,然后递归构造左右子树
写法一
class Solution:def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:# 如果输入数组只有一个元素,将该元素作为树的根节点返回if len(nums) == 1:return TreeNode(nums[0])# 在递归的过程中有可能会遇到空数组的情况,因此需要进行判断if len(nums) != 0:# 计算数组的中间索引,以便将中间元素作为树的根节点index = len(nums) // 2# 创建当前树的根节点,值为数组中间索引处的元素root = TreeNode(nums[index])# 递归构建当前根节点的左子树,传入左半部分的数组作为参数root.left = self.sortedArrayToBST(nums[0:index])# 递归构建当前根节点的右子树,传入右半部分的数组作为参数root.right = self.sortedArrayToBST(nums[index+1:])# 返回当前根节点及其左右子树构成的平衡二叉搜索树return rootelse:# 如果数组为空,则返回 None,表示当前子树为空树return None
写法二:
class Solution:def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:if len(nums) == 1:return TreeNode(nums[0])index = len(nums)//2#向下取整root = TreeNode(nums[index]) #递归构造根节点的左右子平衡树,只有非空才有左右子树if index>0:root.left = self.sortedArrayToBST(nums[0:index])if index<len(nums)-1:root.right = self.sortedArrayToBST(nums[index+1:])return root
主要是要注意区间是否非空,否则会报错:list out of index
538.把二叉搜索树转换为累加树
文档讲解:代码随想录
题目链接:. - 力扣(LeetCode)
依然是在遍历过程中,双指针的应用,需要对遍历过程很熟悉
class Solution:def __init__(self):# 初始化变量 'pre' 用于跟踪当前节点之前所有节点值的总和self.pre = 0def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:if not root:return None# 以逆中序遍历(右-根-左)的方式遍历树,更新节点值self.traversal(root) # 从最右边的节点开始遍历return rootdef traversal(self, cur):if not cur:return None# 递归遍历右子树以累加节点值到 'pre'self.traversal(cur.right) # 从最右边的节点开始遍历cur.val += self.pre # 将当前节点值更新为之前所有节点值的总和self.pre = cur.val # 更新 'pre' 为当前节点值# 递归遍历左子树self.traversal(cur.left) # 继续向左最节点遍历