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. 未初始化内存检测(MSan)

    https://github.com/google/sanitizers/wiki https://github.com/google/sanitizers/wiki/MemorySanitizer ...

  2. 关于Idea突然无法输入的诡异问题解决

    问题描述 最近加班把自己的装有Debian的笔记本带到公司,使用Idea写代码的时候,突然间无法输入,ctrl与tab还可用,重启Idea能得到一阵的解决 解决参考 如果是Linux平台,请考虑是否是 ...

  3. 《数据结构》《C++程序设计》《计算机组成原理》中的英语名词

    一.数据结构 data 数据data element 数据元素data item 数据项data object 数据对象data structure 数据结构ADT (Abstruct Date Ty ...

  4. 微信小程序小Demo

    微信小程序小Demo 调用API,轮播图,排行榜,底部BabTar的使用... board // board/board.js Page({ /** * 页面的初始数据 */ // 可以是网络路径图片 ...

  5. 带你认识MySQL sys schema

    前言:  MySQL 5.7中引入了一个新的sys schema,sys是一个MySQL自带的系统库,在安装MySQL 5.7以后的版本,使用mysqld进行初始化时,会自动创建sys库. sys库里 ...

  6. 车位iou计算

    车位检测中,判断多帧图像检测出的车位是否是同一个车位.计算其IOU. 判断一个点是否在一个四边形内 Approach : Let the coordinates of four corners be ...

  7. Spring源码分析之IOC的三种常见用法及源码实现(三)

    上篇文章我们分析了AnnotationConfigApplicationContext的构造器里refresh方法里的invokeBeanFactoryPostProcessors,了解了@Compo ...

  8. 拒绝CPU挖矿矿工有责

    长期以来CPU挖矿给挖矿行业带来持久的负面影响,因为CPU是电脑的核心设备,一挖矿就干不了别的了,大家是否可以达成共识拒绝CPU挖矿? 显卡挖矿刚好构建在不影响大众的日常工作生活对电脑的需求之上,家用 ...

  9. VMware——安装CentOS

    VMware——安装CentOS 摘要:本文主要记录了在VMware虚拟机里安装CentOS的步骤. 下载操作系统 可以从下面的镜像地址去下载各种版本的CentOS,此次安装使用的版本是7.2: ht ...

  10. Java foreach循环

    foreach循环:增强性的for循环应用: 在for语句中,需要使用索引来进行操作具体的数组或集合内容操作:而foreach可以取消索引的操作细节: for ( 类型 变量 : 数组 | 集合 ) ...