9

LeetCode: 450. Delete Node in a BST

 3 years ago
source link: https://mozillazg.com/2020/09/leetcode-450-delete-node-in-a-bst.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

题目

原题地址:https://leetcode.com/problems/delete-node-in-a-bst/

Given a root node reference of a BST and a key, delete the node with the given key in the BST. Return the root node reference (possibly updated) of the BST.

Basically, the deletion can be divided into two stages:

  1. Search for a node to remove.
  2. If the node is found, delete the node.

Follow up: Can you solve it with time complexity O(height of tree) ?

Example 1:

image
Input: root = [5,3,6,2,4,null,7], key = 3
Output: [5,4,6,2,null,null,7]

Explanation: Given key to delete is 3. So we find the node with value 3 and delete it.
One valid answer is [5,4,6,2,null,null,7], shown in the above BST.
Please notice that another valid answer is [5,2,6,null,4,null,7] and it's also accepted.
image2

Example 2:

Input: root = [5,3,6,2,4,null,7], key = 0
Output: [5,3,6,2,4,null,7]

Explanation: The tree does not contain a node with value = 0.

Example 3:

Input: root = [], key = 0
Output: []

Constraints:

  • The number of nodes in the tree is in the range [0, 104] .
  • -10^5 <= Node.val <= 10^5
  • Each node has a unique value.
  • root is a valid binary search tree.
  • -10^5 <= key <= 10^5

解法

分析所有可能情况然后编写适用所有 case 的代码

从 BST 中删除一个节点会有下面三种情况:

  • 待删除的节点没有子节点,这个是最简单的情况,直接删除这个节点就可以了不需要做对 BST 做额外的调整。
       50                            50
    /     \         delete(20)      /   \
   30      70       --------->    30     70
  /  \    /  \                     \    /  \
20   40  60   80                   40  60   80
  • 待删除的节点只有一个子节点,这种情况下只需要把它跟子节点交换位置,然后再删除就可以了。
    50                            50
 /     \         delete(30)      /   \
30      70       --------->    40     70
  \    /  \                          /  \
  40  60   80                       60   80
  • 待删除的节点有两个子节点,这种情况最复杂,因为如果像第二种情况一下跟子节点交换位置的话,会出现多出一个子节点的情况,无法满足删除节点后仍然是个 BST 的需求,这个方法会导致需要反复调整来重建 BST。这种情况下一个更好的方法是从右侧的子孙节点中找出一个最小的节点(也就是右子数最左侧的那个节点),然后交换位置再删除就可以了。因为是右侧最小的节点,所以它同时满足比左侧子孙节点大比右侧子孙节点小的特性,从而用最小的代价实现了删除节点后仍旧是个 BST 的需求(使用左子数中最大的一个节点进行交换也可以满足这个需求,原因也是一样的)。
    50                            60
 /     \         delete(50)      /   \
40      70       --------->    40    70
       /  \                            \
      60   80                           80

这个方法的 Python 代码类似下面这样:

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def deleteNode(self, root, key):
        if root is None:
            return root

        if root.val == key:
            if root.left is None and root.right is None:
                return None
            if root.left is None or root.right is None:
                return root.left or root.right

            min_node = self.get_min_node(root.right)
            root.val = min_node.val
            min_node.val = key
            root.right = self.deleteNode(root.right, key)

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

        return root

    def get_min_node(self, root):
        while root.left is not None:
            root = root.left
        return root

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK