leetcode450——二叉搜索树删除(py版本)

题目链接:leetcode450

分析

最基本的类型吧,但是实现起来考虑的还是比较烦
整理一下也方便后面的查阅

二叉搜索树的性质就不提了,就是中序遍历是有序的。
查找部分,就是一个简单的迭代,判断当前的root和我们的实际值大小关系,如果相同则直接跳出(我们把这个点叫做root)
找到之后,我们需要对之前的树进行调整,这里我们不需要进行删除操作,只需要修改原树的指向问题即可,剩下的垃圾回收会帮我们搞定。

这里的重点是调整的方式,对于一般的树来说(指那种结点比较多的,可以想成满二叉树?先考虑一般情况么)
我们可以将左子树的最后一个结点或者右子树的第一个结点作为新root
这块,替换的过程中有一个很烦的问题就是我们要修改root和替换结点的同时,还需要修改他们的父节点,那么就需要在遍历的同时记录下来。

接下来就是一些特殊情况的问题,比如我们的root只有单个的孩子结点,或者直接没有孩子?
单个结点可以直接把另一个孩子拉上去,没有节点就直接删除

'''官方的二叉树存储结构'''
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
        # 先找到再说吧
        '''这里的father是root的父节点,old_root是方便我们return用的,branch记录father是通过left还是right到的root
        他这里有一个很骚的逻辑,就是如果我删除的刚好是树中唯一的结点,那么此时树为空,所以我选择给原树直接找了个爹
        这样防止一些边界条件的问题'''
        father, branch = TreeNode(left=root), True
        old_root = father
        while root and root.val != key:
            father = root
            if root.val > key:
                root = root.left
                branch = True
            else:
                root = root.right
                branch = False

        if root:
            # 我们要删除当前的这个位置
            if not (root.left or root.right):
                # 叶子节点,直接删除
                if branch:
                    father.left = None
                else:
                    father.right = None
            elif root.left:
                # 存在左子树,我们直接拉最后一个结点
                '''下面的if分支是对root.left就是last_left的一个补丁,此时我们没法搞last_left_father'''
                # 对于没有右孙子的,我们直接搞
                if not root.left.right:
                    # last_left挪到root
                    last_left = root.left
                    last_left.right = root.right
                else:
                    last_left = root.left
                    last_left_father = root
                    while last_left.right:
                        last_left_father = last_left
                        last_left = last_left.right
                    # 调整最后一个点的左子树
                    last_left_father.right = last_left.left
                    # last_left移动到root
                    last_left.left = root.left
                    last_left.right = root.right
                # 调整father
                if branch:
                    father.left = last_left
                else:
                    father.right = last_left
            else:
                # 只有右子树,直接拉上去
                if branch:
                    father.left = root.right
                else:
                    father.right = root.right
        
        return old_root.left

然后补一个递归的,是仿照leetcode官方解答写的,有两点比较新颖,标了一下

'''递归版本'''
if not root:
    return None
else:
    if root.val > key:
        root.left = self.deleteNode(root.left, key)
    elif root.val < key:
        root.right = self.deleteNode(root.right, key)
    else:
        # 相同了,我们整理子树
        # 此时是要用一个结点替代我们的根节点
        if not root.left:
            return root.right
        elif not root.right:
            return root.left
        else:
            # 我们这次找右子树的第一个结点
            p = root.right
            while p.left:
                p = p.left
            '''他这个函数调用是真的牛,因为我们的目的就是在root的右子树中删除p,
            然后将其接到p的右子树上'''
            p.right = self.deleteNode(root.right, p.val)
            p.left = root.left
        # 因为做了替换,所以这里是p,剩下的是root
        return p
return root
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值