Leetcode 450:删除二叉搜索树中的节点(最详细的解法!!!)

版权声明:本文为博主原创文章,未经博主允许不得转载。有事联系:[email protected] https://blog.csdn.net/qq_17550379/article/details/82344213

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

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

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

说明: 要求算法时间复杂度为 O(h),h 为树的高度。

示例:

root = [5,3,6,2,4,null,7]
key = 3

    5
   / \
  3   6
 / \   \
2   4   7

给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。

一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。

    5
   / \
  4   6
 /     \
2       7

另一个正确答案是 [5,2,6,null,4,null,7]。

    5
   / \
  2   6
   \   \
    4   7

解题思路

这是一个非常经典的问题,我们将通过hibbard deletion来解决这个问题。主要分成如下三种情况:

  • 被删除的节点没有子节点
  • 被删除的节点没有左孩子或右孩子
  • 被删除的节点包含左右孩子



0x01 被删除的节点没有左右孩子




由于它没有子节点,我们直接将该节点置为 null即可。

0x02 被删除的节点没有左孩子或右孩子




无论被删除的节点是包含左孩子还是右孩子,我们直接将该节点唯一的孩子链接到其父节点,然后删除该节点即可。

0x03 被删除的节点包含左右孩子




这是三种情况中最复杂的情况,我们有两种策略:一种是从左子树中选择出左子树中的最大值,用来替换要删除的节点;另一种是,从右子树中选择出右子树中的最小值,用来替换要删除的节点。我们这里使用第二种策略,也就是使用 21替换删除元素 20

这个问题中,我们会面临这样的两个问题:

  • 求右子树最小值

    def minimum(self, root):
      if not root.left:
          return root
    
      return self.minimum(root.left)
  • 删除右子树最小值

    def removeMin(self, root):
      if not root.left:
          right = root.right
          return right
    
      root.left = self.removeMin(root.left)
      return root

剩下的问题就是对这些问题的整合

class Solution:
    def minimum(self, root):
        if not root.left:
            return root

        return self.minimum(root.left)

    def removeMin(self, root):
        if not root.left:
            right = root.right
            return right

        root.left = self.removeMin(root.left)
        return root

    def deleteNode(self, root, key):
        """
        :type root: TreeNode
        :type key: int
        :rtype: TreeNode
        """
        if not root:
            return None

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

            if not root.right:
                return root.left

            tmp = self.minimum(root.right)
            tmp.right = self.removeMin(root.right)
            tmp.left = root.left
            return tmp

同样的,我们对于递归求解的问题都希望尝试是否可以通过迭代去求解。

class Solution(object):
    def deleteNode(self, root, key):
        """
        :type root: TreeNode
        :type key: int
        :rtype: TreeNode
        """
        p = root 
        p_parent = None
        while p and p.val != key:
            p_parent = p
            if p.val > key:
                p = p.left
            else:
                p = p.right

        if not p:
            return root

        p_right_parent = p
        p_right = p.right
        if not p_right: 
            if not p_parent:
                return p.left

            if p_parent.left == p:
                p_parent.left = p.left
            else:
                p_parent.right = p.left
        else:
            while p_right.left:
                p_right_parent = p_right
                p_right = p_right.left

            p.val = p_right.val

            if p_right_parent.left == p_right:
                p_right_parent.left = p_right.right
            else:
                p_right_parent.right = p_right.right

        return root

reference:

http://javabypatel.blogspot.com/2015/08/delete-a-node-from-binary-search-tree-in-java.html

我将该问题的其他语言版本添加到了我的GitHub Leetcode

如有问题,希望大家指出!!!

猜你喜欢

转载自blog.csdn.net/qq_17550379/article/details/82344213