代码随想录算法训练营 二叉树 part8

一、二叉搜索树的最近公共祖先 

235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode)

Krahets大神的解题思路:
祖先的定义: 若节点 p 在节点 root的左(右)子树中,或 p=root,则称 root 是 p 的祖先。

最近公共祖先的定义: 设节点 root 为节点 p,q 的某公共祖先,若其左子节点 root.left 和右子节点 root.right都不是 p,q的公共祖先,则称 root是 “最近的公共祖先” 。

根据以上定义,若 root 是 p,q的 最近公共祖先 ,则只可能为以下三种情况之一:

p 和 q 在 root 的子树中,且分列 root 的 异侧(即分别在左、右子树中)。
p=root 且 q 在 root的左或右子树中;
q=root 且 p 在 root 的左或右子树中;

题目有① 树为 二叉搜索树 ,② 树的所有节点的值都是 唯一 的。根据以上条件,可方便地判断 p,q 与 root 的子树关系,即:

若 root.val<p.val ,则 p 在 root右子树 中。
若 root.val>p.val ,则 p 在 root 左子树 中。
若 root.val=p.val ,则 p 和 root 指向 同一节点 。

递归
递推工作:
当 p,q 都在 root 的 右子树 中,则开启递归 root.right 并返回。
否则,当 p,q 都在 root 的 左子树 中,则开启递归 root.left并返回。
返回值: 最近公共祖先 root 。

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root.val < p.val && root.val < q.val)
            return lowestCommonAncestor(root.right, p, q);
        if (root.val > p.val && root.val > q.val)
            return lowestCommonAncestor(root.left, p, q);
        return root;
    }
}

迭代
循环搜索: 当节点 root为空时跳出。
当 p,q都在 root 的 右子树 中,则遍历至 root.right。
否则,当 p,q都在 root 的 左子树 中,则遍历至 root.left。
否则,说明找到了 最近公共祖先 ,跳出。
返回值: 最近公共祖先 root 。

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        while (root != null) {
            if (root.val < p.val && root.val < q.val) // p,q 都在 root 的右子树中
                root = root.right; // 遍历至右子节点
            else if (root.val > p.val && root.val > q.val) // p,q 都在 root 的左子树中
                root = root.left; // 遍历至左子节点
            else break;
        }
        return root;
    }
}

二、二叉搜索树中的插入操作 

701. 二叉搜索树中的插入操作 - 力扣(LeetCode)

递归解法:

如果 root 是空,则新建树节点作为根节点返回即可。
否则比较 root.val 与目标值的大小关系:
如果 root.val 大于目标值,说明目标值应当插入 root 的左子树中,问题变为了在 root.left 中插入目标值,递归调用当前函数;
如果 root.val 小于目标值,说明目标值应当插入 root 的右子树中,问题变为了在 root.right 中插入目标值,递归调用当前函数。

class Solution {
    public TreeNode insertIntoBST(TreeNode root, int val) {
        if (root == null) {
            return new TreeNode(val);
        }

        if (root.val < val) {
            root.right = insertIntoBST(root.right, val);
        } else {
            root.left = insertIntoBST(root.left, val);
        }
        return root;
    }
}

三、删除二叉搜索树中的节点 

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

根据二叉搜索树的性质

  • 如果目标节点没有子节点,我们可以直接移除该目标节点。
  • 如果目标节只有一个子节点,我们可以用其子节点作为替换。
  • 如果目标节点有两个子节点,我们需要用其中序后继节点或者前驱节点来替换,再删除该目标节点。

class Solution {
    private int getNextValue(TreeNode node) {
        node = node.right;
        while (node.left != null) {
            node = node.left;
        }
        return node.val;
    }

    private int getPrevValue(TreeNode node) {
        node = node.left;
        while (node.right != null) {
            node = node.right;
        }
        return node.val;
    }

    public TreeNode deleteNode(TreeNode root, int key) {
        if (root == null) return null;

        if (root.val > key) { // 当前节点的值大于 key,去左子树上寻找待删除的点
            root.left = deleteNode(root.left, key);
        } else if (root.val < key) { // 当前节点的值小于 key,去右子树上寻找待删除的点
            root.right = deleteNode(root.right, key);
        } else { // 当前节点为待删除的节点
            if (root.left == null && root.right == null) {
                // 1. 如果当前节点是叶子节点,直接删除
                root = null;
            } else if (root.right != null) {
                // 2. 如果当前节点的右子树存在,用下一节点(右子树的最左节点)替换当前节点,并在右子树上删除下一个节点
                root.val = getNextValue(root); // 用下一节点(右子树的最左节点)替换当前节点
                root.right = deleteNode(root.right, root.val); // 去右子树上将下一个节点删除 
            } else {
                // 3. 当前节点的右子树不存在,但是左子树存在时,用上一个节点(左子树最右的节点)替换当前节点,并在左子树上删除上一个节点
                root.val = getPrevValue(root);
                root.left = deleteNode(root.left, root.val);
            }

        }
        return root;
    }
}

四、总结

在各种题解里苟┭┮﹏┭┮

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿玛兰妲。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值