坚持刷题|二叉树的最近公共祖先


Hello,大家好,我是阿月。坚持刷题,老年痴呆追不上我,今天刷:二叉树的最近公共祖先

题目

236.二叉树的最近公共祖先
在这里插入图片描述
在这里插入图片描述

考察点

  • 对二叉树的理解:理解二叉树的基本概念,包括节点、左右子树等。

  • 递归的理解和应用:解决这个问题的常用方法是使用递归。

  • 最近公共祖先的概念:理解最近公共祖先的概念,即两个节点在树中的最低公共祖先节点。

  • 时间复杂度和空间复杂度分析:能够分析算法的时间复杂度和空间复杂度,以及是否能够优化算法。

代码实现

public class LowestCommonAncestor {

    /**
     * 寻找二叉树中两个节点的最近公共祖先
     * @param root 二叉树的根节点
     * @param p 第一个节点
     * @param q 第二个节点
     * @return 最近公共祖先节点
     */
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        // 如果根节点为空,或者根节点等于其中一个目标节点,直接返回根节点
        if (root == null || root == p || root == q) {
            return root;
        }

        // 在左子树中寻找目标节点
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        // 在右子树中寻找目标节点
        TreeNode right = lowestCommonAncestor(root.right, p, q);

        // 如果左子树和右子树分别包含目标节点,说明当前节点为最近公共祖先
        if (left != null && right != null) {
            return root;
        }

        // 如果左子树包含目标节点,则返回左子树的结果
        // 如果右子树包含目标节点,则返回右子树的结果
        return left != null ? left : right;
    }

    public static void main(String[] args) {
        LowestCommonAncestor solution = new LowestCommonAncestor();

        // 创建一个二叉树
        TreeNode root = new TreeNode(3);
        root.left = new TreeNode(5);
        root.right = new TreeNode(1);
        root.left.left = new TreeNode(6);
        root.left.right = new TreeNode(2);
        root.right.left = new TreeNode(0);
        root.right.right = new TreeNode(8);
        root.left.right.left = new TreeNode(7);
        root.left.right.right = new TreeNode(4);

        TreeNode p = root.left;
        TreeNode q = root.right;

        TreeNode result = solution.lowestCommonAncestor(root, p, q);
        System.out.println("最近公共祖先: " + result.val);
    }
}

实现总结

  • 寻找二叉树的公共祖先,是一种自底向上的寻找,而二叉树的回溯过程就是自底向上。
  • 后序遍历(左右中)是天然的回溯过程,可以根据左右子树的返回值,来处理中节点的逻辑。
  • 递归
    • 递归函数返回值以及参数:
      • 返回值:递归函数返回的是最近公共祖先节点。
      • 参数:递归函数的参数包括当前节点 root,以及要查找的两个目标节点 p 和 q。
    • 终止条件:
      • 如果当前节点为空 (root == null),或者当前节点等于 p 或 q,则直接返回当前节点,因为当前节点就是其中一个目标节点的最近公共祖先。
    • 单层递归逻辑:
      • 在每一层递归中,首先向左子树和右子树递归查找目标节点 p 和 q。
      • 如果左子树和右子树都找到了目标节点,则当前节点就是最近公共祖先。
      • 如果只有左子树找到了目标节点,则返回左子树的结果。
      • 如果只有右子树找到了目标节点,则返回右子树的结果。
    • 在递归函数有返回值的情况下:
      • 如果要搜索一条边,递归函数返回值不为空的时候,立刻返回。
      • 如果搜索整个树,直接用一个变量left、right接住返回值,这个left、right后序还有逻辑处理的需要,也就是后序遍历中处理中间节点的逻辑(也是回溯)。
  • 时间复杂度:O(N)。
    • 对于每个节点,都要做一些固定的工作:检查它是否等于目标节点 p 或 q,然后向下递归左右子树。因此,时间复杂度可以表示为 O(N),其中 N 是二叉树中节点的数量。
    • 在最坏的情况下,需要遍历整个二叉树才能找到最近公共祖先节点。因此,时间复杂度是线性的,与二叉树中的节点数量成正比。

为什么不用迭代的方法实现?

迭代法不适合模拟回溯的过程。

  • 复杂性增加:在迭代法中,模拟回溯过程需要使用额外的数据结构,例如栈或队列,来跟踪节点的访问顺序。这增加了实现的复杂性,特别是在处理二叉树的情况下。
  • 代码可读性差:迭代法模拟回溯过程的代码可能会更加复杂,难以理解和调试。相比之下,递归的代码结构更为清晰,更容易表达出问题的解决思路。
  • 空间开销增加:迭代法在模拟回溯过程时可能需要消耗更多的内存空间,特别是对于大型树或搜索空间较大的情况下,栈的空间开销可能会非常高。
  • 性能问题*:在某些情况下,递归的实现可能比迭代的实现更有效率,因为递归天然地利用了函数调用栈,而不需要额外的数据结构来跟踪状态。

虽然迭代法可以实现回溯算法,但通常情况下,递归更适合模拟回溯过程,因为递归天然地具有树形结构,与树、图等数据结构的问题更为契合,实现起来更为简洁清晰。

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

坚持刷题|二叉搜索树的最近公共祖先

  • 26
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Hello 阿月

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

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

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

打赏作者

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

抵扣说明:

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

余额充值