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

文章介绍了在二叉搜索树中查找两个指定节点的最近公共祖先的递归方法,以及如何使用递归法实现二叉搜索树的插入和删除操作,确保树的性质不变。
摘要由CSDN通过智能技术生成

235. 二叉搜索树的最近公共祖先

力扣题目链接(opens new window)

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉搜索树:  root = [6,2,8,0,4,7,9,null,null,3,5]

235. 二叉搜索树的最近公共祖先

示例 1:

  • 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
  • 输出: 6
  • 解释: 节点 2 和节点 8 的最近公共祖先是 6。

示例 2:

  • 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
  • 输出: 2
  • 解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。

说明:

  • 所有节点的值都是唯一的。
  • p、q 为不同节点且均存在于给定的二叉搜索树中。

递归法(版本一)

class Solution:
    def traversal(self, cur, p, q):
        if cur is None:
            return cur
                                                        # 中
        if cur.val > p.val and cur.val > q.val:           # 左
            left = self.traversal(cur.left, p, q)
            if left is not None:
                return left

        if cur.val < p.val and cur.val < q.val:           # 右
            right = self.traversal(cur.right, p, q)
            if right is not None:
                return right

        return cur

    def lowestCommonAncestor(self, root, p, q):
        return self.traversal(root, p, q)

首先,定义了一个名为Solution的类,其中包含两个方法:traversallowestCommonAncestor

  • traversal方法是一个递归函数,它接收三个参数:当前节点和两个需要找到最低公共祖先的节点。在每次递归调用中,我们首先检查当前节点是否为空。如果为空,则直接返回。然后,我们比较当前节点的值和两个目标节点的值。如果当前节点的值大于两个目标节点的值,那么我们知道最低公共祖先必然在当前节点的左子树中,因此我们递归地在左子树中查找。同样地,如果当前节点的值小于两个目标节点的值,那么我们知道最低公共祖先必然在当前节点的右子树中,因此我们递归地在右子树中查找。如果当前节点的值介于两个目标节点的值之间,那么我们知道当前节点就是最低公共祖先,因此我们返回当前节点。

  • lowestCommonAncestor方法则是用于找出二叉搜索树中两个给定节点的最低公共祖先。它接收三个参数:一个二叉搜索树的根节点和两个需要找到最低公共祖先的节点。这个方法调用了traversal方法来进行查找,并返回查找到的结果。

701.二叉搜索树中的插入操作

力扣题目链接(opens new window)

给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据保证,新值和原始二叉搜索树中的任意节点值都不同。

注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回任意有效的结果。

701.二叉搜索树中的插入操作

提示:

  • 给定的树上的节点数介于 0 和 10^4 之间
  • 每个节点都有一个唯一整数值,取值范围从 0 到 10^8
  • -10^8 <= val <= 10^8
  • 新值和原始二叉搜索树中的任意节点值都不同

递归法(版本二)

class Solution:
    def insertIntoBST(self, root, val):
        if root is None:
            return TreeNode(val)
        parent = None
        cur = root
        while cur:
            parent = cur
            if val < cur.val:
                cur = cur.left
            else:
                cur = cur.right
        if val < parent.val:
            parent.left = TreeNode(val)
        else:
            parent.right = TreeNode(val)
        return root

这段代码的目标是在二叉搜索树中插入一个新的节点。下面是代码的详细步骤:

  1. 首先,检查根节点是否为空。如果为空,那么新的节点就会成为根节点。
  2. 如果根节点不为空,那么就会进入一个循环,直到找到合适的位置来插入新的节点。在这个循环中,代码会检查新值是否小于当前节点的值。
  3. 如果新值小于当前节点的值,那么代码会向左子树移动;否则,它会向右子树移动。在每一步中,都会更新父节点为当前节点。
  4. 当找到合适的位置(即当前节点为空)时,代码会检查新值是否小于父节点的值。如果是,那么新节点将被插入到父节点的左侧;否则,它将被插入到父节点的右侧。
  5. 最后,函数返回根节点。

这个函数假设给定的二叉树是一个有效的二叉搜索树,并且没有重复的值。

450.删除二叉搜索树中的节点

力扣题目链接(opens new window)

给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。

一般来说,删除节点可分为两个步骤:

首先找到需要删除的节点; 如果找到了,删除它。 说明: 要求算法时间复杂度为 $O(h)$,h 为树的高度。

示例:

450.删除二叉搜索树中的节点

 

递归法(版本一)

class Solution:
    def deleteNode(self, root, key):
        if root is None:
            return root
        if root.val == key:
            if root.left is None and root.right is None:
                return None
            elif root.left is None:
                return root.right
            elif root.right is None:
                return root.left
            else:
                cur = root.right
                while cur.left is not None:
                    cur = cur.left
                cur.left = root.left
                return root.right
        if root.val > key:
            root.left = self.deleteNode(root.left, key)
        if root.val < key:
            root.right = self.deleteNode(root.right, key)
        return root

这段代码的目标是删除二叉搜索树中的一个节点。二叉搜索树是一种特殊的树,其中每个节点的左子节点的值都小于该节点的值,右子节点的值都大于该节点的值。

  1. 首先,我们检查根节点是否为空,如果为空,那么我们没有什么可以删除的,所以直接返回空。
  2. 然后,我们检查根节点的值是否等于我们要删除的值。如果是,那么我们需要删除这个节点。这里有几种情况:
    • 如果这个节点没有子节点(即它是一个叶子节点),那么我们可以直接删除它,返回None。
    • 如果这个节点只有一个子节点,那么我们可以通过返回它的子节点来替换它。
    • 如果这个节点有两个子节点,那么事情就变得复杂了。我们需要找到右子树中的最小值(也就是右子树中最左边的节点),然后用这个最小值来替换要删除的节点。
  3. 如果根节点的值大于我们要删除的值,那么我们知道要删除的节点在左子树中,所以我们对左子树递归调用删除函数。
  4. 如果根节点的值小于我们要删除的值,那么我们知道要删除的节点在右子树中,所以我们对右子树递归调用删除函数。
  5. 最后,无论发生什么情况,我们都返回根节点。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值