力扣(LeetCode)450.删除二叉搜索树中的节点(Java)

一、目标

  给定一个二叉搜索树的根节点 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;

三、总结

因为最后一种情况涉及要大幅度变更二叉树的结构,所以思路稍微有些复杂。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值