0
点赞
收藏
分享

微信扫一扫

450. 删除二叉搜索树中的节点 : 简单递归运用题

题目描述

这是 LeetCode 上的 ​​450. 删除二叉搜索树中的节点 ,难度为 中等

Tag : 「递归」、「BST」

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

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

  • 首先找到需要删除的节点;
  • 如果找到了,删除它。

示例 1: 450. 删除二叉搜索树中的节点 : 简单递归运用题_递归

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

450. 删除二叉搜索树中的节点 : 简单递归运用题_递归_02

另一个正确答案是 [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

输出: []

提示:

  • 节点数的范围450. 删除二叉搜索树中的节点 : 简单递归运用题_子树_03
  • 450. 删除二叉搜索树中的节点 : 简单递归运用题_算法_04
  • 节点值唯一
  • root 是合法的二叉搜索树
  • 450. 删除二叉搜索树中的节点 : 简单递归运用题_递归_05

进阶: 要求算法时间复杂度为 450. 删除二叉搜索树中的节点 : 简单递归运用题_递归_06450. 删除二叉搜索树中的节点 : 简单递归运用题_Java_07 为树的高度。

递归

利用题目本身的函数签名的含义,也就是「在以 ​​root​​ 为根的子树中,删除值为 ​​key​​ 的节点,并返回删除节点后的树的根节点」,我们可以用「递归」来做。

起始先对边界情况进行处理,当 ​​root​​​ 为空(可能起始传入的 ​​root​​​ 为空,也可能是递归过程中没有找到值为 ​​key​​​ 的节点时,导致的 ​​root​​​ 为空),我们无须进行任何删除,直接返回 ​​null​​ 即可。

根据当前 ​​root.val​​​ 与 ​​key​​ 的大小关系,进行分情况讨论:

  1. 若有450. 删除二叉搜索树中的节点 : 简单递归运用题_子树_08,说明待删除的节点必然不是当前节点,以及不在当前节点的左子树中,我们将删除动作「递归」到当前节点的右子树,并将删除(可能进行)之后的新的右子树根节点,重新赋值给​​​root.right​​​,即有​​root.right = deleteNode(root.right, key)​​;
  2. 若有450. 删除二叉搜索树中的节点 : 简单递归运用题_后端_09,说明待删除的节点必然不是当前节点,以及不在当前节点的右子树,我们将删除节点「递归」到当前节点的左子树,并将删除(可能进行)之后的新的左子树根节点,重新赋值给​​​root.left​​​,即有​​root.left = deleteNode(root.left, key)​​;
  3. 若有450. 删除二叉搜索树中的节点 : 简单递归运用题_后端_10,此时找到了待删除的节点,我们根据左右子树的情况,进行进一步分情况讨论:
  • 若左/右子树为空,我们直接返回右/左子树节点即可(含义为直接将右/左子树节点搬到当前节点的位置)如图所示:450. 删除二叉搜索树中的节点 : 简单递归运用题_递归_11
  • 若左右子树均不为空,我们有两种选择:
  • 从「当前节点的左子树」中选择「值最大」的节点替代​​root​​​ 的位置,确保替代后仍满足​​BST​​ 特性;
  • 从「当前节点的右子树」中选择「值最小」的节点替代​​root​​​ 的位置,确保替代后仍满足​​BST​​ 特性;

我们以「从当前节点的左子树中选择值最大的节点」为例子,我们通过树的遍历,找到其位于「最右边」的节点,记为 450. 删除二叉搜索树中的节点 : 简单递归运用题_Java_12450. 删除二叉搜索树中的节点 : 简单递归运用题_Java_12 作为最右节点,必然有 ​​​t.right = null​​​),利用原本的 ​​root​​​ 也是合法 ​​BST​​​,原本的 ​​root.right​​​ 子树的所有及节点,必然满足大于 ​​t.val​​​,我们可以直接将 ​​root.right​​​ 接在 ​​t.right​​​ 上,并返回我们重接后的根节点,也就是 ​​root.left​​。

而「从当前节点的右子树中选择值最小的节点」,同理(代码见 450. 删除二叉搜索树中的节点 : 简单递归运用题_算法_14)。



代码:

class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) return null;
if (root.val == key) {
if (root.left == null) return root.right;
if (root.right == null) return root.left;
TreeNode t = root.left;
while (t.right != null) t = t.right;
t.right = root.right;
return root.left;
} else if (root.val < key) root.right = deleteNode(root.right, key);
else root.left = deleteNode(root.left, key);
return root;
}
}

class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) return null;
if (root.val == key) {
if (root.left == null) return root.right;
if (root.right == null) return root.left;
TreeNode t = root.right;
while (t.left != null) t = t.left;
t.left = root.left;
return root.right;
} else if (root.val < key) root.right = deleteNode(root.right, key);
else root.left = deleteNode(root.left, key);
return root;
}
}
  • 时间复杂度:450. 删除二叉搜索树中的节点 : 简单递归运用题_递归_06,其中450. 删除二叉搜索树中的节点 : 简单递归运用题_Java_07为树的深度
  • 空间复杂度:忽略递归带来的额外空间消耗,复杂度为450. 删除二叉搜索树中的节点 : 简单递归运用题_算法_17

最后

这是我们「刷穿 LeetCode」系列文章的第 ​​No.450​​ 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。

在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。

为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:github.com/SharingSour… 。

在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。

举报

相关推荐

0 条评论