一、目标
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
首先找到需要删除的节点; 如果找到了,删除它。 说明: 要求算法时间复杂度为 $O(h)$,h 为树的高度。

二、代码解读
删除二叉搜索树的节点涉及多个情况,比较繁琐
总体代码:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if(root == null){
return null;
}
if(key == root.val){
//待删除的节点就是叶子节点;
if(root.right == null && root.left == null){
return null;
}
//待删除的节点下的子节点左不为空右为空;
else if(root.left != null && root.right == null){
return root.left;
}
//待删除的节点下的子节点右不为空右左为空;
else if(root.right != null && root.left == null){
return root.right;
}
//待删除的节点下的子节点都不为空;
else{
TreeNode cur = root.right;
while(cur.left != null){
cur = cur.left;
}
cur.left = root.left;
return root.right;
}
}
if(key < root.val){root.left = deleteNode(root.left, key);}
if(key > root.val){root.right = deleteNode(root.right, key);}
return root;
}
}
递归第一步:确定递归终止条件
遍历到空节点为止,return回null即可
public TreeNode deleteNode(TreeNode root, int key) {
if(root == null){
return null;
}
递归第二布:确定单层处理逻辑
如果遍历到当前节点判断为要删除的节点,本题的处理首先是这样的:
待删除的节点的子节点会出现以下几种情况:
待删除的节点就是叶子节点;
待删除的节点下的子节点左不为空右为空;
待删除的节点下的子节点右不为空右左为空;
待删除的节点下的子节点都不为空;
注:给上一层的节点接住的逻辑在递归的最后一步确定,本题的大逻辑就是把待删除的节点返回给上一层(待删除子节点的上一层)的对应节点接住(类似于链表删除,直接将上一层的指针指向待删除节点的下一个节点就可以了,但是要分情况处理)
待删除的节点就是叶子节点:
这种情况最简单,直接return空给上一层的节点接住就行
待删除的节点下的子节点左不为空右为空 || 待删除的节点下的子节点右不为空右左为空:
直接将不为空的子节点返回给上一层去接住,改变上一层的指针直接绕过当前待删除节点
待删除的节点下的子节点都不为空:
这种情况最复杂,先假设当前待删除节点的左子节点为A,右子节点为B,处理逻辑为先让A或者B去继承当前待删除节点的位置,然后将A的节点直接接在B以下的子树的最左下的节点(因为二叉搜索树的特性,最左下的节点一定是和A点值差的最少的,也就是最左下的节点只会比A点值大一点点,可以从二叉搜索树中序遍历是一个递增数组去理解),这样处理最稳妥。
if(key == root.val){
//待删除的节点就是叶子节点;
if(root.right == null && root.left == null){
return null;
}
//待删除的节点下的子节点左不为空右为空;
else if(root.left != null && root.right == null){
return root.left;
}
//待删除的节点下的子节点右不为空右左为空;
else if(root.right != null && root.left == null){
return root.right;
}
//待删除的节点下的子节点都不为空;
else{
TreeNode cur = root.right;
while(cur.left != null){
cur = cur.left;
}
cur.left = root.left;
return root.right;
}
}
递归第三部,递归调取定义的方法:
如果当前节点的值大于key,那应该去左边搜,然后用root.left接住;
如果当前节点的值小于key,那应该去右边搜,然后用root.right接住;
最后返回该节点就可以
if(key < root.val){root.left = deleteNode(root.left, key);}
if(key > root.val){root.right = deleteNode(root.right, key);}
return root;
三、总结
因为最后一种情况涉及要大幅度变更二叉树的结构,所以思路稍微有些复杂。

619

被折叠的 条评论
为什么被折叠?



