leetcode_450 删除二叉搜索树中的节点

177 阅读3分钟

要求

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

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

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

示例 1:

image.png

输入:root = [5,3,6,2,4,null,7], key = 3
输出:[5,4,6,2,null,null,7]
解释:给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。
一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。
另一个正确答案是 [5,2,6,null,4,null,7]。

image.png 示例 2:

输入: root = [5,3,6,2,4,null,7], key = 0
输出: [5,3,6,2,4,null,7]
解释: 二叉树不包含值为 0 的节点

示例 3:

输入: root = [], key = 0
输出: []

核心代码

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]:
        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

image.png

重点问题

解题思路:

根据题目要求,我们肯定是要从上到下进行搜索的。其次,我们也要充分利用BST的性质,可以在每轮递归中比较key和根节点的大小,决定到左子树还是右子树里搜寻,如何进行删除? 删除节点主要有三种情况:

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

这里我们优先采用右子树替换根节点的原则(当然左子树也可以)。 当我们找到需要删除的节点后,必须以右子树的最小节点(也就是右子树最左的节点)来代替被删除的节点,以下图的例子来说明:

image.png

这幅图中,如果我们删除节点3,则必须以先节点4替换节点3,再在下两轮递归中,把节点3去掉。
这样才能保持BST的性质不发生变化,满足题目要求。

实际上我们在操作的过程中是先在搜索树中进行搜索,决定要删除那个节点,然后我们看要删除节点是否是叶子节点,叶子节点直接删除即可;是否有左子树或者是否有右子树(单一存在),存在单一左右子树我们直接将剩下的拼接上去即可;假设左右子树都存在,那么我们就需要保证我们删除节点之后,仍然保持这个树是一个搜索二叉树,我们采用的是使用右子树中最左下方的点来替代要删除节点(这个删除实际上是替换),最终别忘了将替换的节点也进行删除(这个才是实际的删除),非常好的一道题。