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.

Note: Time complexity should be O(height of tree).

Example:

root = [5,3,6,2,4,null,7]
key = 3 5
/ \
3 6
/ \ \
2 4 7 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 following BST. 5
/ \
4 6
/ \
2 7 Another valid answer is [5,2,6,null,4,null,7]. 5
/ \
2 6
\ \
4 7

这道题让我们删除二叉搜索树中的一个节点,难点在于删除完结点并补上那个结点的位置后还应该是一棵二叉搜索树。被删除掉的结点位置,不一定是由其的左右子结点补上,比如下面这棵树:

7
        / \
       4   8
     /   \   
    2     6
     \   /
      3 5

如果要删除结点4,那么应该将结点5补到4的位置,这样才能保证还是 BST,那么结果是如下这棵树:

7
        / \
       5   8
     /   \   
    2     6
     \   
      3

先来看一种递归的解法,首先判断根节点是否为空。由于 BST 的左<根<右的性质,使得可以快速定位到要删除的结点,对于当前结点值不等于 key 的情况,根据大小关系对其左右子结点分别调用递归函数。若当前结点就是要删除的结点,先判断若有一个子结点不存在,就将 root 指向另一个结点,如果左右子结点都不存在,那么 root 就赋值为空了,也正确。难点就在于处理左右子结点都存在的情况,需要在右子树找到最小值,即右子树中最左下方的结点,然后将该最小值赋值给 root,然后再在右子树中调用递归函数来删除这个值最小的结点,参见代码如下:

解法一:

class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (!root) return NULL;
if (root->val > key) {
root->left = deleteNode(root->left, key);
} else if (root->val < key) {
root->right = deleteNode(root->right, key);
} else {
if (!root->left || !root->right) {
root = (root->left) ? root->left : root->right;
} else {
TreeNode *cur = root->right;
while (cur->left) cur = cur->left;
root->val = cur->val;
root->right = deleteNode(root->right, cur->val);
}
}
return root;
}
};

下面来看迭代的写法,还是通过 BST 的性质来快速定位要删除的结点,如果没找到直接返回空。遍历的过程要记录上一个位置的结点 pre,如果 pre 不存在,说明要删除的是根结点,如果要删除的结点在 pre 的左子树中,那么 pre 的左子结点连上删除后的结点,反之 pre 的右子结点连上删除后的结点。在删除函数中,首先判空,若为空,直接返回空指针;否则检测若右子结点不存在,直接返回左子结点即可,因为没有右子树就不会牵扯到调整树结构的问题;若右子结点存在,需要找到右子树中的最小值,即右子树中的最左子结点,用一个 while 循环找到即可,然后将要删除结点的左子结点连到右子树的最左子结点的左子结点上即可(说的有点绕,大家仔细体会一下),最后返回要删除结点的右子结点即可,文字表述确实比较绕,请大家自行带例子一步一步观察就会很清晰明了,参见代码如下:

解法二:

class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (!root) return nullptr;
TreeNode *cur = root, *pre = nullptr;
while (cur) {
if (cur->val == key) break;
pre = cur;
if (cur->val > key) cur = cur->left;
else cur = cur->right;
}
if (!pre) return del(cur);
if (pre->left && pre->left->val == key) pre->left = del(cur);
else pre->right = del(cur);
return root;
}
TreeNode* del(TreeNode* node) {
if (!node) return nullptr;
if (!node->right) return node->left;
TreeNode *t = node->right;
while (t->left) t = t->left;
t->left = node->left;
return node->right;
}
};

下面来看一种对于二叉树通用的解法,适用于所有二叉树,所以并没有利用 BST 的性质,而是遍历了所有的结点,然后删掉和 key 值相同的结点,参见代码如下:

解法三:

class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (!root) return NULL;
if (root->val == key) {
if (!root->right) return root->left;
else {
TreeNode *cur = root->right;
while (cur->left) cur = cur->left;
swap(root->val, cur->val);
}
}
root->left = deleteNode(root->left, key);
root->right = deleteNode(root->right, key);
return root;
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/450

类似题目:

Split BST

参考资料:

https://leetcode.com/problems/delete-node-in-a-bst/

https://leetcode.com/problems/delete-node-in-a-bst/discuss/93296/Recursive-Easy-to-Understand-Java-Solution

https://leetcode.com/problems/delete-node-in-a-bst/discuss/93378/An-easy-understanding-O(h)-time-O(1)-space-Java-solution.

https://leetcode.com/problems/delete-node-in-a-bst/discuss/93331/concise-c-iterative-solution-and-recursive-solution-with-explanations

https://leetcode.com/problems/delete-node-in-a-bst/discuss/93293/Very-Concise-C%2B%2B-Solution-for-General-Binary-Tree-not-only-BST

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] 450. Delete Node in a BST 删除二叉搜索树中的节点的更多相关文章

  1. [LeetCode] 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. Retur ...

  2. 450 Delete Node in a BST 删除二叉搜索树中的结点

    详见:https://leetcode.com/problems/delete-node-in-a-bst/description/ C++: /** * Definition for a binar ...

  3. Java实现 LeetCode 450 删除二叉搜索树中的节点

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

  4. [Swift]LeetCode450. 删除二叉搜索树中的节点 | 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. Retur ...

  5. LeetCode 530. Minimum Absolute Difference in BST (二叉搜索树中最小绝对差)

    Given a binary search tree with non-negative values, find the minimum absolute difference between va ...

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

    思路: (1)如果root为空,返回 (2)如果当前结点root是待删除结点: a:root是叶子结点,直接删去即可 b:root左子树不为空,则找到左子树的最大值,即前驱结点,使用前驱结点代替待删除 ...

  7. [LeetCode] Inorder Successor in BST II 二叉搜索树中的中序后继节点之二

    Given a binary search tree and a node in it, find the in-order successor of that node in the BST. Th ...

  8. [CareerCup] 4.6 Find Next Node in a BST 寻找二叉搜索树中下一个节点

    4.6 Write an algorithm to find the'next'node (i.e., in-order successor) of a given node in a binary ...

  9. [leetcode]450. Delete Node in a BST二叉搜索树删除节点

    二叉树变量只是一个地址 public static void main(String[] args) { TreeNode t = new TreeNode(3); help(t); System.o ...

随机推荐

  1. 一位IT民工的十年风雨历程

    距离2020年只有30天了,转眼毕业快10年. 回首自己,已三十有三,中年危机. 古人云三十而立,我却还在测试途中摸爬滚打. 创业,自由职业永远是一个梦,白日梦. 焦虑.迷茫.看不到希望. 这两天一场 ...

  2. vue入门案例

    1.技术在迭代,有时候你为了生活没有办法,必须掌握一些新的技术,可能你不会或者没有时间造轮子,那么就先把利用轮子吧. <!DOCTYPE html> <html> <he ...

  3. C#面试基础知识点:值类型和引用类型(1)(填坑文)

    目录 前言 C#值类型和引用类型 基类(共同点) 值类型继承基类(不同点) 应用类型继承 技术经理的问题 值类型与引用类型都可以用Equals来比较吗? 如何将一个数组a的值赋予数组b然后对b做修改而 ...

  4. 在Linux系统中运行并简单的测试RabbitMq容器

    以前使用的是Windows下面的RabbitMq,需要先安装 Erlang的语言环境等,这次直接在Linux中的Docker容器来测试一下 1:docker配置RabbitMq的指令 docker r ...

  5. Linux帮助——获取帮助

    Linux帮助——获取帮助 摘要:本文主要学习了Linux众多命令中最基础的帮助命令. 介绍 作用 Linux的所有操作都可以通过命令行来完成,所以学习Linux最好从命令行开始.因为Linux的命令 ...

  6. flask-script、flask-admin组件

    目录 flask-script 安装 使用 自定制命令 flask-admin 安装 简单使用 将表模型注册到admin中 如果有个字段是图片字段 flask-script 用于实现类似于django ...

  7. Asp.Net MVC强类型页面获取值几种方式

    方式一 (V:视图) @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="v ...

  8. js 设计模式——代理模式

    代理模式 代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问. 生活中有很多的代理模式的场景.例如,明星有经纪人作为代理,老板有秘书作为代理等等,当有事情的时候,会找到经纪人或秘书,再由他 ...

  9. MQTT实战1 - 使用Apache Apollo代理服务器实现mqtt通信

    MQTT实战1 - 使用Apache Apollo代理服务器实现mqtt通信 MQTT实战2 - 使用MQTTnet实现mqtt通信 源码下载 -> 提取码  QQ:505645074 MQTT ...

  10. [20190502]给显示输出加入时间戳.txt

    [20190502]给显示输出加入时间戳.txt --//有别人问我执行脚本中timestamp.pl的代码,实际上有些文章里面有源代码,有一些忘记写上了.--//贴上:$ cat /usr/loca ...