目录
450.删除二叉搜索树中的节点
题目描述
解题思路
删除节点意味着改变二叉树的结构(因为删除完还需要保证二叉搜索树的特性)
1. 没找到要删的节点
2. 找到了要删的节点:
i) 要删的是叶子结点(没有左右子节点,比较好删因为不用改变结构)
ii) 要删的节点只有左子节点,右为空,则直接让上上层的节点指向当前节点的左子节点
iii) 要删的节点只有右子节点,左为空(情况和ii一致)
iv) 要删的节点左右子节点都不为空,(选择让右子节点继位)则先将该节点的父节点指向该节点的右子节点,再将该节点的左子树放在右子节点的左子结点(为什么是右子节点的左子结点因为该节点是比当前要删节点的稍微大一点的数字,即大于要删的节点仅次于要删的节点的右子节点的节点)的左子树位置
【同理也可以选择如果让左子节点继位,则将该节点的父节点指向该节点的左子节点,再将该节点的右子树放在左子节点的右子节点的右子树位置】
引用自代码随想录该题的动图,理解第五种情况(左右子节点都不为空,选择让右子节点继位的情况)
代码
递归的终止条件:(删除节点的逻辑也在终止条件里)找到要删除的节点
没找到要删的节点
找到了要删的节点
【1. 是叶子结点(如果左子树和右子树都是空则return null,把该节点变成null再往上一层递归返回)】
【2. 左不为空右为空(如果左子树不是空,右子树是空,则把该节点变成这个节点的左子树,进而可以往上一层递归返回让他接住这个返回值)】
【3. 同理左为空右不为空,则和2同逻辑,只是返回的是节点的右子树】
【4. 要删的节点左右子节点都不为空,选择让右子节点继位的情况:需要将cur = root.right(也就是把操作指针定位到要删的节点的右子节点,然后一直找这个操作指针的最左子结点(也就是while (cur.left != null)),找到了则把操作指针变成当前操作指针的左子结点(cur = cur.left),这样才能方便后续的子树移动操作)再把要删的节点的左子树放在当前操作指针的左子树(cur.left = root.left)最后直接让右子节点继位(return root.right)】
单层递归的逻辑:
如果要删的值小于根节点的值,则往左子树递归遍历【注意:因为递归会返回一个节点,因此需要用root.left去接住】(if (key < root.val) root.left = delete(root.left, key))
同理如果要删的值大于根节点的值,则相同逻辑
最后再返回root
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
// 终止条件:找到删除的节点
// 1. 没找到
if (root == null) return null;
// 2. 找到了
if (root.val == key) {
// i) 叶子节点:则返回null
if (root.left == null && root.right == null) return null;
// ii) 如果是左空右不为空:则返回root.right
else if (root.left == null && root.right != null) return root.right;
// iii) 如果是左不为空右为空:则返回root.left
else if (root.left != null && root.right == null) return root.left;
// iv) 如果是左不为空右也不为空(选择右子节点继位的情况):让root的左子树移动到右子节点的左子结点的左子树位置,返回root.right
else {
// 先把操作节点移动到root的右子节点
TreeNode cur = root.right;
// 再一直找root的右子节点的最左子节点,找到了之后把操作指针移动到这个节点
while (cur.left != null) cur = cur.left;
// 然后将root的左子树移动到右子节点的左子结点的左子树位置
cur.left = root.left;
// 让右子节点继位,即返回root.right
return root.right;
}
}
// 单层递归的逻辑
// 如果目标值小于root值则到左子树递归遍历
// 由于递归遍历有一个返回值所以需要拿对应的值接住(即左子树遍历则用root.left)
if (key < root.val) root.left = deleteNode(root.left, key);
// 同理大于root值则到右子树遍历(即右子树遍历则用root.right)
else if (key > root.val) root.right = deleteNode(root.right, key);
// 返回root值
return root;
}
}