Leetcode450. 删除二叉搜索树中的节点

LeetCode 450:删除二叉搜索树中的节点
本文详细解析了LeetCode 450题——删除二叉搜索树中的节点的解决方案,包括递归和迭代两种方法。通过具体示例,讲解了如何定位并删除目标节点,同时保持二叉搜索树的特性。

Leetcode450. 删除二叉搜索树中的节点

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

题解:
方案一:递归:

  • 如果 key>root.valkey > root.valkey>root.val,说明要删除的节点在右子树,root.right=deleteNode(root.right,key)root.right = deleteNode(root.right,key)root.right=deleteNode(root.right,key)
  • 如果 key<root.valkey < root.valkey<root.val,说明要删除的节点在左子树,root.left=deleteNode(root.left,key)root.left = deleteNode(root.left,key)root.left=deleteNode(root.left,key)
  • 如果 key==root.valkey == root.valkey==root.val,则该节点就是我们要删除的节点,则:
      1.如果该节点是叶子节点,则直接删除它:root=nullroot = nullroot=null
      2.如果该节点不是叶子节点且有右节点,则用它的后继节点的值替代 root.val=successor.valroot.val = successor.valroot.val=successor.val,然后删除后继节点。
      3.如果该节点不是叶子节点且只有左节点,则用它的前驱节点的值替代 root.val=predecessor.valroot.val = predecessor.valroot.val=predecessor.val,然后删除前驱节点。
  • 返回 root。

方案二:迭代

java代码:

/**
     * 递归
     *
     * @param root
     * @param key
     * @return
     */
    public static TreeNode deleteNode2(TreeNode root, int key) {
        if (root == null) return null;
        if (root.value > key) root.left = deleteNode2(root.left, key);
        else if (root.value < key) root.right = deleteNode2(root.right, key);
        else {
            if (root.left == null && root.right == null) root = null;
            else if (root.right != null) {
                root.value = successor(root);
                root.right = deleteNode2(root.right, root.value);

            } else {
                root.value = predecessor(root);
                root.left = deleteNode2(root.left, root.value);
            }
        }
        return root;
    }


    /**
     * 找右子树的最小值
     *
     * @param root
     * @return
     */
    public static int successor(TreeNode root) {
        root = root.right;
        while (root.left != null) root = root.left;
        return root.value;
    }

    /**
     * 找左子树的最大值
     *
     * @param root
     * @return
     */
    public static int predecessor(TreeNode root) {
        root = root.left;
        while (root.right != null) root = root.right;
        return root.value;

    }

迭代:

 /**
     * 二叉搜索树的中序遍历的序列是递增排序的序列
     * 迭代
     *
     * @param root
     * @param key
     * @return
     */
    public static TreeNode deleteNode(TreeNode root, int key) {
        TreeNode cur = root;
        TreeNode parent = null;
        //找到要删除的节点
        while (cur != null && cur.value != key) {
            parent = cur;
            if (cur.value > key) {
                cur = cur.left;
            } else if (cur.value < key) {
                cur = cur.right;
            }
        }

        if (cur == null) return root;

        if (cur.left == null && cur.right == null) {
            //删除的节点不是根节点
            if (parent != null) {
                if (parent.left == cur) {
                    parent.left = null;
                } else {
                    parent.right = null;
                }
            } else {
                //整个树只有一个节点
                return null;
            }
            //左节点或者右节点其中有一个为null
        } else if (cur.left == null || cur.right == null) {
            TreeNode sub = cur.left == null ? cur.right : cur.left;
            cur.value = sub.value;
            cur.left = sub.left;
            cur.right = sub.right;
            sub.left = null;
            sub.right = null;
            //左右节点都不为null,找到左子树中的最大值,替换到key节点
        } else {
            TreeNode sub = cur.left;
            //右子树为null
            if (sub.right == null) {
                cur.left = sub.left;
                cur.value = sub.value;
                sub.left = null;
            } else {
                parent = sub;
                while (sub.right != null) {
                    parent = sub;
                    sub = sub.right;
                }
                parent.right = sub.left;
                cur.value = sub.value;
                sub.left = null;
            }
        }
        return root;

    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值