zoukankan      html  css  js  c++  java
  • 450. 删除二叉搜索树中的节点

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

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

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

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

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

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

    示例 1:

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

    示例 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;
    };

     

  • 相关阅读:
    14. 最长公共前缀-字符串-简单
    13. 罗马数字转整数-字符串-简单
    12. 整数转罗马数字-字符串-中等难度
    48. 旋转图像-数组-中等难度
    6. Z 字形变换-字符串-中等难度
    39. 组合总和-dfs回溯-中等难度
    【STM32F407开发板用户手册】第23章 STM32F407的USART串口基础知识和HAL库API
    【STM32F429开发板用户手册】第22章 STM32F429的SysTick实现多组软件定时器
    【STM32F407开发板用户手册】第22章 STM32F407的SysTick实现多组软件定时器
    【STM32F429开发板用户手册】第21章 STM32F429的NVIC中断分组和配置(重要)
  • 原文地址:https://www.cnblogs.com/wltree/p/15698331.html
Copyright © 2011-2022 走看看