450. 删除二叉搜索树中的节点

450. 删除二叉搜索树中的节点

题目链接:450. 删除二叉搜索树中的节点(中等)

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

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

  1. 首先找到需要删除的节点;

  2. 如果找到了,删除它。

示例 1:

450. 删除二叉搜索树中的节点

输入: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], 如下图所示。

450. 删除二叉搜索树中的节点

示例 2:

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

示例 3:

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

提示:

  • 节点数的范围 [0, 104].

  • -105 <= Node.val <= 105

  • 节点值唯一

  • root 是合法的二叉搜索树

  • -105 <= key <= 105

解题思路

在删除二叉搜索树中的节点时,需要考虑到五种情况:

有以下五种情况:

  • 第一种情况:没找到待删除节点,遍历到空节点就直接返回NULL

  • 找到待删除节点

    • 第二种情况:待删除节点的左右孩子都为空(叶子节点),直接删除待删除节点, 返回NULL为根节点

    • 第三种情况:待删除节点的左孩子为空,右孩子不为空,删除待删除节点,右孩子补位,返回右孩子为根节点

    • 第四种情况:待删除节点的右孩子为空,左孩子不为空,删除待删除节点,左孩子补位,返回左孩子为根节点

    • 第五种情况:待删除节点的左右孩子都不为空,则将左孩子 转成 右孩子最左边的孩子,再删除节点,返回右孩子作为根节点。(或 第五种情况:待删除节点的左右孩子都不为空,则将右孩子 转成 左孩子最右边的孩子,再删除节点,返回左孩子作为根节点。)

C++

//递归(前序遍历)
class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        // 第一种情况:没有找到需要删除的节点,遇到空节点直接返回
        if (root == nullptr) return root;
        // 找到需要删除的节点
        if (key == root->val) {
            // 第二种情况:被删除节点的左右孩子都为空,则直接删除该节点,并返回NULL为根节点
            if (root->left == nullptr && root->right == nullptr) {
                delete root;
                return nullptr;
            } // 第三种情况:被删除节点的左孩子为空,右孩子不为空,则删除该节点,右孩子补位,返回右孩子为根节点
            else if (root->left == nullptr && root->right != nullptr) {
                TreeNode* temp = root->right;
                delete root;
                return temp;
            } // 第四种情况:被删除节点的右孩子为空,左孩子不为空,则删除该节点,左孩子补位,返回左孩子为根节点
            else if (root->left != nullptr && root->right == nullptr) {
                TreeNode* temp = root->left;
                delete root;
                return temp;
            } // 第五种情况:被删除节点的左右孩子都不为空,则将左孩子 转成 右孩子最左边的孩子,再删除节点,返回右孩子作为根节点。
            // 或 第五种情况:被删除节点的左右孩子都不为空,则将右孩子 转成 左孩子最右边的孩子,再删除节点,返回左孩子作为根节点。
            else {
                TreeNode* cur = root->right;
                while (cur->left) {
                    cur = cur->left;
                }
                cur->left = root->left;
                TreeNode* temp = root;
                root = root->right;
                delete temp;
                return root;
            }
        }
​
        // 被删除节点的值 小于 当前节点的值,往当前节点的左子树去寻找
        if (key < root->val) root->left = deleteNode(root->left, key);
        // 被删除节点的值 大于 当前节点的值,往当前节点的右子树去寻找
        if (key > root->val) root->right = deleteNode(root->right, key);
        return root;
    }
};

JavaScript

/**
 * 递归
 * @param {TreeNode} root
 * @param {number} key
 * @return {TreeNode}
 */
var deleteNode = function(root, key) {
    if (root === null) return root;
​
    if (root.val === key) {
        if (root.left === null && root.right === null) {
            delete root;
            return null;
        } else if (root.left === null && root.right != null) {
            let temp = root;
            root = root.right;
            delete temp;
            return root;
        } else if (root.left != null && root.right === null) {
            let temp = root;
            root = root.left;
            delete temp;
            return root;
        } else {
            let cur = root.right;
            while (cur.left) {
                cur = cur.left;
            }
            cur.left = root.left;
            let temp = root;
            root = root.right;
            delete temp;
            return root;
        }
    }
​
    if (root.val > key) root.left = deleteNode(root.left, key);
    if (root.val < key) root.right = deleteNode(root.right, key);
    return root;
};

 

上一篇:[计算机基础]字符编码是什么?


下一篇:19.javascript 常用的数学方法