LeetCode 450.删除二叉搜索树中的节点(Python实现)

题目要求

题目给定一个二叉搜索树的根节点 root 和一个值 key。
要求删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。
一般来说,删除节点可分为两个步骤:

  • 首先找到需要删除的节点;
  • 如果找到了,删除它。

其次要求算法时间复杂度为 O(h),h 为树的高度
LeetCode 450.删除二叉搜索树中的节点(Python实现)

解题思路

如何找到需要删除的节点?

根据题目要求,我们肯定是要从上到下进行搜索的。其次,我们也要充分利用BST的性质,可以在每轮递归中比较key和根节点的大小,决定到左子树还是右子树里搜寻(这些技巧我们在LeetCode 236中也用到过)

如何进行删除?

删除节点主要有三种情况:

  • 节点只存在左子树,那么我们直接用左子树代替根节点即可;
  • 节点只存在右子树,同样地,我们直接用右子树代替根节点;
  • 同时存在左右子树是比较复杂的情况,这是我们重点关注的情况。

这里我们优先采用右子树替换根节点的原则(当然左子树也可以)。
当我们找到需要删除的节点后,必须以右子树的最小节点(也就是右子树最左的节点)来代替被删除的节点,以下图的例子来说明:
LeetCode 450.删除二叉搜索树中的节点(Python实现)
这幅图中,如果我们删除节点3,则必须以先节点4替换节点3,再在下两轮递归中,把节点3去掉。
这样才能保持BST的性质不发生变化,满足题目要求,下面给出代码。

class Solution(object):
    def deleteNode(self, root, key):
        """
        :type root: TreeNode
        :type key: int
        :rtype: TreeNode
        """
        if not root:
            return None
        #到左子树里搜索
        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 or not root.right:
                root = root.left if root.left else root.right
            else:
                temp = root.right
                # 找到右子树的最小(最左)节点
                while temp.left: 
                    temp = temp.left
                root.val = temp.val
                # 继续在右子树里递归
                root.right = self.deleteNode(root.right, temp.val)
            
        return root