1 题目描述
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
首先找到需要删除的节点;
如果找到了,删除它。
示例 1:
输入: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],另一个正确答案是 [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
输出: []
2 算法设计
二叉排序树的删除情况较复杂,有下面三种情况需要考虑:
- 删除叶子节点(如:2,5,9,12)
- 删除只有一棵子树的节点(如:1)
- 删除有两棵子树的节点(如:7,3,10)
思路分析:
第一种情况:删除叶子节点(如:2,5,9,12)
(1)找到要删除的节点
(2)直接删除节点, 返回NULL为根节点
第二种情况:删除只有一棵子树的节点(如:1)
(1)找到要删除的节点
(2)判断该节点有左孩子节点还是右孩子节点
(3)若左孩子节点为空:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点;若右孩子为空:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
第三种情况:删除有两棵子树的节点(如:7,3,10)
(1)找到要删除的节点
(2)用一个临时变量保存目标节点右子树最左的叶子结点
(3)将目标节点的左子树最为目标节点右子树中最左边叶子结点的左子树
(4)将目标节点的右孩子节点赋值给目标节点(删除目标节点)
3 代码实现
public TreeNode deleteNode(TreeNode root, int key) {
//递归的出口
if (root == null) return root;
//若找到值为key的目标节点
if (root.val == key){
//节点左孩子节点为空,右孩子不为空,直接返回右节点
if (root.left == null){
return root.right;
}else if (root.right == null){ //节点右孩子节点为空,左孩子节点不为空,直接返回左节点
return root.left;
}else { //节点的左右孩子节点都不为空
TreeNode cur = root.right;
//寻找节点右子树上最左边的叶节点
while (cur.left !=null){
cur = cur.left;
}
//将节点的左子树作为cur节点左子树
cur.left = root.left;
//将root节点的右孩子节点赋值给root节点,删除root节点
root = root.right;
return root;
}
}
//继续向左右子树递归
//这里相当于把新的节点返回给上一层,上一层就要用 root->left 或者 root->right接住,代码如下:
if (root.val > key) root.left = deleteNode(root.left,key);
if (root.val < key) root.right = deleteNode(root.right,key);
return root;
}