Leetcode 450. 删除二叉搜索树中的节点-精简迭代法

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

题目就是简单的删除 二叉搜索树中的一个节点而已。

一、迭代法

分情况考虑的话,思路清晰又简单:

  1. 待删除节点无子节点时:
    那就直接将 指向待删除节点的指针,置空即可
  2. 待删除节点有一个子节点时:
    将 指向待删除节点的指针 指向 待删除节点的儿子(需要判断是左儿子还是右儿子)
  3. 待删除节点有两个子节点:
    找到待删除节点右子树中的最小值,来替换掉待删除节点。

我们知道,想要删除某个节点,肯定要先找到这个节点,迭代法去找的话,那一定要用两个指针的,一个用来正在查找的位置,另一个记录此位置的父节点(因为删除节点时,需要知道此节点的父节点嘛)

所以java代码如下:

(1)查找待删除的点:

TreeNode p=root;//利用p去遍历,保留root不动,最后得返回root
TreeNode pp=null;//p的父节点

while(p!=null&&p.val!=key){
    
    
    pp=p;
    if(key<p.val) p=p.left;
    else p=p.right;
}//此循环结束后,p就是待删除的节点,pp是p的父节点

if(p==null) return root;//没有找到待删除的值

(2)待删除节点无子节点

//如果p没有孩子,则直接把pp指向置空
if(p.left==null&&p.right==null) {
    
    
if(pp.left==p) pp.left=null;
if(pp.right==p) pp.right=null;
}

(3)待删除节点有一个子节点时:

 //如果p只有一个孩子,那直接把孩子换上来即可
TreeNode child=null;
if(p.left==null&&p.right!=null) child=p.right;
if(p.left!=null&&p.right==null) child=p.left;
if(pp.left==p) pp.left=child;
if(pp.right==p) pp.right=child;

(4)待删除节点有两个子节点:

//如果p有左右子树,那就将其右子树的最小值来替换p
        if(p.left!=null&&p.right!=null){
    
    
            TreeNode rp=p.right;
            TreeNode rpp=p;
            while(rp.left!=null){
    
    
                rpp=rp;
                rp=rp.left;
            }//循环结束后,rp就是要找的右子树的最小值,rpp是其父节点
            //将rpp指向rp的指针置空
            if(rpp.left==rp) rpp.left=null;
            if(rpp.right==rp) rpp.right=null;
            //将待删除节点的val换上
            p.val=rp.val;
        }

但是呢,像上面这样就要有很多的if去判断所出现的各种情况,非常繁琐。
发现了大神的精简的写法:
观察到上述,一定都有将指针置空和将指针重新指向的过程。
所以大神的方法是将这两个步骤合起来,让三种情况共用一组指针置空和重新指向的过程。
java代码如下:

/**
 * 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) {
    
    
        TreeNode p=root;//利用p去遍历,保留root不动,最后得返回root
        TreeNode pp=null;//p的父节点

        while(p!=null&&p.val!=key){
    
    
            pp=p;
            if(key<p.val) p=p.left;
            else p=p.right;
        }//此循环结束后,p就是待删除的节点,pp是p的父节点
        
        if(p==null) return root;//没有找到待删除的值



        //如果p有左右子树,那就将其右子树的最小值来替换p
        if(p.left!=null&&p.right!=null){
    
    
            TreeNode rp=p.right;
            TreeNode rpp=p;
            while(rp.left!=null){
    
    
                rpp=rp;
                rp=rp.left;
            }//循环结束后,rp就是要找的右子树的最小值,rpp是其父节点
            
            //将待删除节点的val换上
            p.val=rp.val;
            //将rpp指向rp的指针置空
            //if(rpp.left==rp) rpp.left=null;
            //if(rpp.right==rp) rpp.right=null;
            p=rp;
            pp=rpp;
        }
        //!!!此方法的这里不好理解!!!
        //删除节点是叶子节点或仅有一个子节点
        TreeNode child;//p的子节点
        if(p.left!=null) child=p.left;
        else if(p.right!=null) child=p.right;
        else child=null;

        if(pp==null) root=child;//删除的是根节点
        else if(pp.left==p) pp.left=child;
        else pp.right=child;

        return root;
        
    }
}

二、递归法

/**
 * 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){
    
    
            root.left=deleteNode(root.left,key);
        }else if(key>root.val){
    
    
            root.right=deleteNode(root.right,key);
        }else{
    
    //root节点正是待删除的值
            if(root.left==null){
    
    //当前节点没有左子树
                return root.right;
            }else if(root.right==null){
    
    
                return root.left;
            }else{
    
    //当前节点有左右子树,将左子树直接放到右子树的最小节点左侧即可
                //找右子树的最小节点
                TreeNode minP=root.right;
                while(minP.left!=null){
    
    
                    minP=minP.left;
                }//minP即为右子树的最小节点
                minP.left=root.left;
                return root.right;
            }
        }
        return root;       
    }
}

猜你喜欢

转载自blog.csdn.net/xiaohaigary/article/details/112290753