代码随想录算法训练营第二十五天|235. 二叉搜索树的最近公共祖先 、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点

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 root
        else:
            # 如果数组为空,则返回 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 = 0

    def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if not root:
            return None

        # 以逆中序遍历(右-根-左)的方式遍历树,更新节点值
        self.traversal(root)  # 从最右边的节点开始遍历
        return root

    def 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)  # 继续向左最节点遍历

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值