[leetCode]450. 删除二叉搜索树中的节点

递归

需要想清楚五种情况如注释所示,利用递归的返回值来删除目标节点

class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        // 第一种情况,没有找到删除节点直接返回null
        if (root == null) return root;
        if (root.val == key) {
            // 第二种情况,左右孩子都为空(叶子节点)直接返回null
            // 第三种情况,左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
            if (root.left == null) return root.right;
            // 第四种情况,右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
            else if (root.right == null) return root.left;
            // 第五种情况,左右孩子都不为空,则将删除节点的左子树放到删除节点的右子树最左面节点的左孩子
            // 并返回删除节点的右孩子为新的根节点
            else {
                TreeNode cur = root.right;
                while (cur.left != null) { // 找到右子树最左面的节点
                    cur = cur.left;
                }
                cur.left = root.left; // 把要删除的节点的左子树放在cur的左孩子位置
                root = root.right; // 返回root右孩子作为新root
                return root;
            }
        }
        if (root.val > key) root.left = deleteNode(root.left, key);
        if (root.val < key) root.right = deleteNode(root.right, key);
        return root;
    }
}

使用删除二叉树节点的方法

代码中目标节点(要删除的节点)被操作了两次:

第一次是和目标节点的右子树最左面节点交换。
第二次直接被NULL覆盖了。

class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        if (root == null) return root;
        if (root.val == key) {
            if (root.right == null) return root.left; // 这里是第二次操作目标值起到删除作用
            TreeNode cur = root.right;
            while (cur.left != null) {
                cur = cur.left;
            }
            // 交换删除节点与删除节点右子树最左边节点的值
            swap(cur, root);
        }
        root.left = deleteNode(root.left, key);
        
        root.right = deleteNode(root.right, key);
        return root;
    }

    private void swap(TreeNode p, TreeNode q) {
        int tmp = p.val;
        p.val = q.val;
        q.val = tmp;
    }
}

迭代

class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        if (root == null) return root;
        TreeNode cur = root;
        TreeNode pre = null; // 记录父节点,用来删除cur
        while (cur != null) {
            if (cur.val == key) break;
            pre = cur;
            if (cur.val > key) cur = cur.left;
            else cur = cur.right;
        }
        if (pre == null) { // 如果搜索树只有头节点
            return deleteOneNode(cur);
        }
        // pre 要知道删除的是左孩子还是右孩子
        if (pre.left != null && pre.left.val == key) {
            pre.left = deleteOneNode(cur);
        }
        if (pre.right != null && pre.right.val == key) {
            pre.right = deleteOneNode(cur);
        }
        return root;
    }

    // 将目标节点的左子树连接到目标节点的右子树最左边的节点上
    // 返回目标节点的右孩子作为新的根节点
    private TreeNode deleteOneNode(TreeNode target) {
        if (target == null) return target;
        if (target.right == null) return target.left;
        TreeNode cur = target.right;
        while (cur.left != null) {
            cur = cur.left;
        }
        cur.left = target.left;
        return target.right;
    }
}
posted @ 2020-11-04 22:04  消灭猕猴桃  阅读(192)  评论(0编辑  收藏  举报