450. 删除二叉搜索树中的节点
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
首先找到需要删除的节点;
如果找到了,删除它。
提示:
- 节点数的范围 [0, 104].
- -105 <= Node.val <= 105
- 节点值唯一
- root 是合法的二叉搜索树
- -105 <= key <= 105
解题思路:递归+迭代
有以下五种情况:
- 第一种情况:没找到删除的节点,遍历到空节点直接返回了
- 找到删除的节点
- 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
- 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
- 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
- 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。
递归的话,先序遍历和后序遍历都可以,但是这里可以利用二叉搜索树的性质,直接用值进行判断,具体代码实现如下。
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if(root == null){
return null;
}
if(root.val > key){
root.left = deleteNode(root.left,key);
}else{
root.right = deleteNode(root.right,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.left = root.left;
root = root.right;
return root;
}
}
return root;
}
}
迭代,需要一个pre指针记录前一个结点,cur指针用来返回root结点,代码如下:
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if(root == null){
return null;
}
TreeNode cur = root;
TreeNode pre = null;
while(root != null){
if(root.val == key){
break;
}
pre = root;
if(root.val > key){
root = root.left;
}else{
root = root.right;
}
}
if(pre == null){
return delete(root);
}
if(pre.left != null && pre.left.val == key){
pre.left = delete(root);
}
if(pre.right != null && pre.right.val == key){
pre.right = delete(root);
}
return cur;
}
private TreeNode delete(TreeNode root){
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.left = root.left;
root = root.right;
return root;
}
}
}
总结:二叉搜索树这里我们一要注意到二叉搜索树的中序遍历特点,而就是它自身独特的查找方式。