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] Delete Node in a BST 删除二叉搜索树中的节点的更多相关文章

  1. [LeetCode] 450. 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. Leetcode450. 删除二叉搜索树中的节点

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

  6. [LeetCode] Insert into a Binary Search Tree 二叉搜索树中插入结点

    Given the root node of a binary search tree (BST) and a value to be inserted into the tree, insert t ...

  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. LeetCode 530. Minimum Absolute Difference in BST (二叉搜索树中最小绝对差)

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

  9. [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 ...

随机推荐

  1. Vertica 导出数据测试用例

    需求:构建简单的测试用例,完成演示Vertica导出数据的功能. 测试用例:导出test业务用户t_jingyu表中的数据. 一.初始化测试环境 二.导出数据 2.1 vsql命令说明帮助 2.2 导 ...

  2. 读书笔记--SQL必知必会20--管理事务处理

    20.1 事务处理 使用事务处理(transaction processing),通过确保成批的SQL操作要么完全执行,要么完全不执行,来维护数据库的完整性. 如果没有错误发生,整组语句提交给数据库表 ...

  3. 你真的会玩SQL吗?表表达式,排名函数

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  4. PHP用单例模式实现一个数据库类

    使用单例模式的出发点: 1.php的应用主要在于数据库应用, 所以一个应用中会存在大量的数据库操作, 使用单例模式, 则可以避免大量的new 操作消耗的资源. 2.如果系统中需要有一个类来全局控制某些 ...

  5. CSS知识总结(四)

    CSS常用样式 2.元素样式 1)宽度 width:auto|length 单位:设置以像素计的宽度值(px) 设置以百分比计的宽度值(%) 例:p {width:200px;} div {width ...

  6. 利用Python进行数据分析(9) pandas基础: 汇总统计和计算

    pandas 对象拥有一些常用的数学和统计方法.   例如,sum() 方法,进行列小计:   sum() 方法传入 axis=1 指定为横向汇总,即行小计:   idxmax() 获取最大值对应的索 ...

  7. Hadoop学习之旅三:MapReduce

    MapReduce编程模型 在Google的一篇重要的论文MapReduce: Simplified Data Processing on Large Clusters中提到,Google公司有大量的 ...

  8. 自己动手写计算器v1.1

    这个改动主要是使用工厂模式替代了简单工厂模式,这样做的好处是如果以后我们要扩充其他运算时,就不用总是去修改工厂类, 这是可以采取工厂模式,主要是将原来简单工厂类的逻辑判断分离出来,将它作为一个借口,与 ...

  9. Java中的多线程你只要看这一篇就够了

    学习Java的同学注意了!!! 学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:279558494 我们一起学Java! 引 如果对什么是线程.什么是进程仍存有疑惑, ...

  10. Hibernate一对多单向(双向)关联映射

    (1).编写配置文件 Hibernate通过读写默认的XML配置文件hibernate.cfg.xml加载数据库配置信息.代码如下: <hibernate-configuration> & ...