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. 详解 IaaS、PaaS和SaaS 以及他们各自的代表公司

    ——IaaS,PaaS和SaaS 是云计算领域的专业术语,也是云计算的三种服务模式.   (1)SaaS:Software as a Service,软件即服务(也称为云应用程序服务) . 云市场中企 ...

  2. Linux socket program Demo1(client & server)

    client  and  server Demo of socket. client send data to server. server send data to client. // this ...

  3. mysql-新增数据库

    一.新增数据库 1.检查mysql 新增数据库之前,先检查是否安装了数据库,本次我们使用的是mysql数据库,检查是否安装mysql直接使用 mysql --version即可: 显示了mysql的版 ...

  4. 5个你可能不知道的html5语义化标签

    1.<ruby>:该标签作用为注释(中文注音或字符),比如可实现下面样式  详见:https://www.w3cschool.cn/html5/html5-ruby.html 2.< ...

  5. python yield: send, close, throw

    send 1. yield可以产出值,可以接收值 2. 在调用send发送非none值之前,我们必须启动一次生成器, 方式有两种 a. gen.send(None) b. next(gen) def ...

  6. 初探云原生应用管理(二): 为什么你必须尽快转向 Helm v3

    系列介绍:这个系列是介绍如何用云原生技术来构建.测试.部署.和管理应用的内容专辑.做这个系列的初衷是为了推广云原生应用管理的最佳实践,以及传播开源标准和知识.在这个系列文章的开篇初探云原生应用管理(一 ...

  7. Beats Elastic中的Auditbeat使用介绍

    Auditbeat使用介绍 Auditbeat是一种轻量级的数据收集器,您可以将其安装在服务器上,以审核系统上用户和进程的活动. 例如,您可以使用Auditbeat从Linux Audit Frame ...

  8. Python传入参数的几种方法

    写在前面 Python唯一支持的参数传递方式是『共享传参』(call by sharing) 多数面向对象语言都采用这一模式,包括Ruby.Smalltalk和Java(Java的引用类型是这样,基本 ...

  9. pip下载速度慢解决方法

    添加镜像链接 解决方式: 更改pip的数据源.目前国内比较知名的有豆瓣的,清华的.都是pipy官网的镜像. 清华:https://pypi.tuna.tsinghua.edu.cn/simple 阿里 ...

  10. linux应用管理

    desktop文件的几个位置: /usr/share/applications ~/.local/share/applications /usr/local/share/applications li ...