原题
给定一个二叉搜索树的根节点 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
解法
思想
删除一个节点,可以有三种情况:
- 它没有子节点,那么直接删除。
- 它拥有一个子节点,那么直接用子节点替换它
- 它有两个子节点,则可以:
将它的右子节点附在左子节点的最右边:

或,将它的左子节点附在右子节点的最左边:

实际就是让搜索树线性化,这样操作会让搜索树的高度逐渐失衡,所以并不推荐作为一个数据结构这样实现。
更好的删除方法可以参考官方题解: https://leetcode-cn.com/problems/delete-node-in-a-bst/solution/shan-chu-er-cha-sou-suo-shu-zhong-de-jie-dian-by-l/
代码
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if(root == null) return null;
if(root.val == key) {//根节点就是要删除的节点
if(root.left==null && root.right==null) return null;
else if(root.left!=null){
TreeNode node = root.left;
while(node.right!=null){
node = node.right;
}
node.right = root.right;
return root.left;
}else return root.right;
}
if(root.left!=null&&root.left.val==key){//左子节点是要删除的节点
if(root.left.left==null && root.left.right==null) root.left = null;
else if(root.left.left!=null){
TreeNode node = root.left.left;
while(node.right!=null){
node = node.right;
}
node.right = root.left.right;
root.left = root.left.left;
}else root.left = root.left.right;
}else if(root.right!=null&&root.right.val==key){//右子节点是要删除的节点
if(root.right.left==null && root.right.right==null) root.right = null;
else if(root.right.right!=null){
TreeNode node = root.right.right;
while(node.left!=null){
node = node.left;
}
node.left = root.right.left;
root.left = root.right.right;
}else root.right = root.right.left;
}else {
deleteNode(root.left,key);
deleteNode(root.right,key);
}
return root;
}
}
原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/leetcode450-%e5%88%a0%e9%99%a4%e4%ba%8c%e5%8f%89%e6%90%9c%e7%b4%a2%e6%a0%91%e4%b8%ad%e7%9a%84%e8%8a%82%e7%82%b9/