代码随想录day22

235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode) 

由于是二叉搜索树,当节点值在p、q之间时,节点就是最近公共祖先,因为此时p、q分别在节点左右子树上;当节点值小于p、q,则往右子树搜索;当节点值大于p、q,则往左子树搜索。

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if not root:
            return None
        if root == q or root == p:
            return root

        if root.val < p.val and root.val < q.val:
            return self.lowestCommonAncestor(root.right, p, q)
        elif root.val > p.val and root.val > q.val:
            return self.lowestCommonAncestor(root.left, p, q)
        else:
            return root

 

701. 二叉搜索树中的插入操作 - 力扣(LeetCode) 

首先排除测试样例的root为空;

比较当前节点值与插入值,向下访问左、右孩子。若待插入位置为空,直接添加节点即可;若不为空,递归调用函数,传入子树根节点和插入值。

* 所以这里不需要root.left = self.insertIntoBST(root.left, val),而是直接调用:self.insertIntoBST(root.left, val)。

class Solution:
    def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
        if not root:
            return TreeNode(val = val)
            
        if root.val < val:
            if not root.right:
                root.right = TreeNode(val = val)
            else:
                self.insertIntoBST(root.right, val)

        else:
            if not root.left:
                root.left = TreeNode(val = val)
            else:
                self.insertIntoBST(root.left, val)

        return root

450. 删除二叉搜索树中的节点 - 力扣(LeetCode)

解法一:用两个递归函数,一个找待删除节点,另一个返回删除后的子树。用待删除节点的左子树的最右侧节点替换待删除节点。

self.deleteNode():若目标小于当前值,到左子树找目标,并将左子树修改为删除后的子树,否则对右子树操作。若目标==当前值,找到待删除节点,设置全局变量,将待删除节点的左子树传入self.func()。

func()需要找到这个左子树最右侧的节点node,将node替换待删除节点就可以保持二叉搜索树的特性(也可以传入右子树,找最左侧节点,替换待删除节点)。全局变量self.pre保存左子树当前访问节点的父节点,self.isfirst指示是否首次调用self.func(),self.left和self.right分别是待删除节点原来的左右孩子。之所以用self.isfirst分两种情况处理,是因为self.isfirst==True时,node是其父节点的左子,否则是其右子。

若待删除节点左孩子为空,直接将它的右子树向上移动替换掉待删除节点即可,即返回它的右孩子。

若首次调用self.func()就访问到没有右孩子的节点node,就将以node为根的子树整体向上移动,node替换掉删除的节点,self.right成为node的右孩子,返回node。

否则,将self.isfirst设为False,更新self.pre,递归访问当前节点右孩子并返回

若在self.isfirst==False时遇到没有右孩子的节点node,1)先将node删掉:将node的左孩子赋给self.pre.right;2)将node移动到原本待删除节点的位置将其替换:将self.left和self.right赋给node.left和node.right,返回node。

class Solution:

    def func(self, root):
        if not root:
            return self.pre.right
        
        if not root.right: 
            if self.isfirst:
                root.right = self.right
                return root
            else:
                self.pre.right = root.left
                root.left = self.left
                root.right = self.right
                return root
                
        self.isfirst = False
        self.pre = root
        return self.func(root.right)

    def deleteNode(self, root, key: int):
        if not root:
            return None

        if root.val == key:
            self.pre = root
            self.left = root.left
            self.right = root.right
            self.isfirst = True
            return self.func(root.left)

        if root.val > key:
            root.left = self.deleteNode(root.left, key)
        else:
            root.right = self.deleteNode(root.right, key)
        
        return root

解法二:将待删除节点的左子树移动到待删除节点右子树的最左侧节点的左孩子位置。

更简洁直观,不容易出错。

class Solution:

    def deleteNode(self, root, key: int):
        if not root:
            return None

        if root.val == key:
            if not root.left:
                return root.right
            if not root.right:
                return root.left

            if root.left and root.right:
                cur = root.right
                while cur.left:
                    cur = cur.left
                cur.left = root.left
                return root.right

        if root.val > key:
            root.left = self.deleteNode(root.left, key)
        else:
            root.right = self.deleteNode(root.right, key)
        
        return root

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值