java数据结构与算法刷题-----LeetCode236. 二叉树的最近公共祖先

文章讲述了如何使用递归方法在二叉树中寻找两个节点的最低公共祖先,介绍了普通递归算法的时间复杂度和优化思路,以及优化后的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.youkuaiyun.com/grd_java/article/details/123063846

在这里插入图片描述

解题思路:时间复杂度O(n),空间复杂度O(n)
  1. 使用深度优先递归遍历(采用前序遍历),递归返回值为可能得公共祖先
  1. p和q两个结点本身,都可能为公共祖先
  2. 如果当前结点,左子树和右子树分别找到了p和q,那么他就是公共祖先
  1. 出口条件为,如果当前结点为null,那就返回null
  1. 但是如果当前结点正好是p和q的一个,那就返回当前结点
  1. 不是出口时,判断条件:当前结点如果不是p或q,并且不为空
  1. 前序遍历其左子树,保存其返回的可能为公共祖先的结点
  2. 然后使用同样操作来前序遍历其右子树
  1. 当前结点左右子树遍历完成后
  1. 如果左子树返回值为null,那么有可能性存在于右子树,返回右子树
  2. 如果左子树不为null,说明在左子树找到p和q中一个
  3. 则判断右子树是否为null,如果是,那么右子树out,只需要返回左子树
  4. 如果左子树和右子树都不为null,说明左右子树都找到了p和q。那么当前root结点为公共祖先,返回root即可

1. 普通递归

代码:因为官方增加了测试用例,目前相同的算法,以前可以达到5ms,现在只能达到7ms。所以只能击败82%的用户,不是算法比他们的慢

在这里插入图片描述
在这里插入图片描述

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        //如果root为null表示前序遍历到了需要回溯的时候,返回null,表示没找到p和q
        if(root == null || root == p || root == q) return root;//但是如果root就是p和q中的一个,直接开始返回,表示找到了p或q
        //前序遍历,获取返回值,返回值为p或q
        TreeNode left = lowestCommonAncestor(root.left, p, q);//如果没找到p和q,就前序遍历继续找
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        //如果left == null,说明当前结点的左子树没找到p或q
        if(left == null) return right;//返回右子树
        //如果left找到了p或q,但是right == null,说明右子树没找到,返回left
        if(right == null) return left;
        //如果当前left和right都不为null,也就是left和right都找到了p和q,那么当前结点就是最近祖先结点,返回即可。
        return root;
    }
}

2. 优化细节

优化思路
  1. 直接可以找到的公共祖先直接跳过返回
  1. 如果p 和 q是同一个结点,那么这个结点本身就是公共祖先
  2. 如果p是q的直接孩子,或者q是p的直接孩子,那么p或q就是最近公共祖先
  1. 前序遍历完成后,返回前,判断进行优化
  1. 不在进行left == null直接返回right,会多判断一次
  2. 改成如下形式,虽然代码多了,但是进入整体判断流程大大缩短
if (left != null && right != null) return root;//如果左右子树都找到了,那么当前结点root是最近公共祖先
else if (left != null && right == null) return left;//如果右子树是null,但是左子树找到了p或q,返回left
else if (left == null && right != null) return right;//如果左子树是null,但右子树找到p或q,返回right
else return null;//如果啥都没找到,返回null
代码:此时,优化后的代码,就非常接近官方增加测试用例数量前的效率了。

在这里插入图片描述

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (p == q) return q;//如果p和q指向同一个结点,直接返回
        if (p.left == q || p.right == q)return p;//如果p结点的直接孩子是q,返回p
        if (q.left == q || q.right == p) return q;//如果q结点的直接孩子是p,返回q
        return traversal(root, p, q);//如果不是上面的3种情况,则需要递归找
    }

    public TreeNode traversal(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) return null;//前序遍历,当前结点为null返回null
        if (root == q || root == p) return root;//如果是p和q的一个,直接返回
        //然后继续前序遍历
        TreeNode left = traversal(root.left, p, q);
        TreeNode right = traversal(root.right, p, q);
        if (left != null && right != null) return root;//如果左右子树都找到了,那么当前结点root是最近公共祖先
        else if (left != null && right == null) return left;//如果右子树是null,但是左子树找到了p或q,返回left
        else if (left == null && right != null) return right;//如果左子树是null,但右子树找到p或q,返回right
        else return null;//如果啥都没找到,返回null
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ydenergy_殷志鹏

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

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

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

打赏作者

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

抵扣说明:

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

余额充值