题目描述
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
- 首先找到需要删除的节点;
- 如果找到了,删除它。
说明: 要求算法时间复杂度为 O(h),h 为树的高度。
root = [5,3,6,2,4,null,7]
key = 3
5
/ \
3 6
/ \ \
2 4 7
给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。
一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。
5
/ \
4 6
/ \
2 7
另一个正确答案是 [5,2,6,null,4,null,7]。
5
/ \
2 6
\ \
4 7
解题思路
BST删除等于等于给定值的节点,分几种情况:
- 递归版:找到要删除的节点,删除它的同时保持BST特性
- 如果
root.val < key
,那么继续从它的右子树中寻找并删除; - 如果
root.val > key
,那么继续从它的左子树中寻找并删除; - 如果
root.val == key
,为表述方便,记要删除的节点为keyNode
,分3种情况:- 若
keyNode
为叶子节点,那么删除后返回null
给其父节点继承; - 若
keyNode
只有左子树,那么删除后返回key.left
给其父节点继承; - 若
keyNode
只有右子树,那么删除后返回key.right
给其父节点继承; - 若
keyNode
左右子树都有,那么从右子树中寻找一个节点继承keyNode.left
,然后返回keyNode.right
给其父节点继承;
- 若
- 如果最终
root
为null
,说明找不到要删除的节点,应该返回原本的BST
;
- 如果
其他解法:
- https://blog.csdn.net/ccj_ok/article/details/76575643
- https://www.cnblogs.com/libaoquan/p/7142767.html
我的实现
递归法(java)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) { // 递归到 root 为 null ,说明找不到要删的节点
return root;
}
if (key < root.val) { // 要删的节点在左子树,删完保持BST特性
root.left = deleteNode(root.left, key);
} else if (key > root.val) { // 要删的节点在右子树,删完保持BST特性
root.right = deleteNode(root.right, key);
} else { // 找到了要删除的节点
if (root.left == null && root.right == null) { // 如果是叶子节点,删了返回null给其父节点即可
return null;
} else if (root.left != null && root.right == null) { // 如果左不空而右空,父节点继承它的左子树即可
return root.left;
} else if (root.left == null && root.right != null) { // 如果右不空而左空,父节点继承它的右子树即可
return root.right;
} else { // 左右都不空,在右子树寻找一个节点继承左子树
TreeNode last = null; // 在右子树继承root.left子树的节点
TreeNode currentRoot = root.right; // 进入右子树
while (currentRoot != null) {
last = currentRoot;
currentRoot = currentRoot.left; // 一直往左走,走到空
}
last.left = root.left; // 继承
return root.right; // 父节点继承修改后得到新子树
}
}
return root;
}
}