算法学习(23)普通二叉树的最近公共祖先问题

文章介绍了如何利用后序遍历的方法在给定的二叉树中查找两个指定节点的最近公共祖先。通过递归实现,当在左子树或右子树找到p或q时,返回上一层,直至找到它们的公共祖先。
摘要由CSDN通过智能技术生成

题目:LeetCode236
给定一个二叉树,找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

示例:
在这里插入图片描述
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点5和节点1的最近公共祖先是节点3。

方法:用后序遍历法,实现从下往上遍历。
1、首先是遍历左子树,如果左子树出现了p或者是q,就返回上一层;
2、返回上一层之后就遍历右子树,如果右子树出现了p或者是q,也返回上一层;
3、当root的左子树有返回值,右子树也有返回值,此时就找到了。
当然上面说的比较宽泛,当root找到p或者q时,就把root的值不断向上返回。

具体代码实现:
1、向下调用的截止条件…
2、返回时的代码写法:
①如果left和right都不为null,说明p和q分别在root的两侧;
②如果left不为空,right为空时,返回left;
③如果right不为空,left为空时,返回right;
④如果left和right都为null,说明在该子树root里p和q一个都没找到,直接返回null即可;
注意:根据代码随想录所讲,当root本身就是p或者q时,为什么不用单独分出来写代码,因为在向下调用的截止条件里已经写了,当root等于p或者q时,会向上返回root,所以不用再单独写了。

一些自己的总结(也许不太对,但大概率是对的):
1、本题代码很清晰明了,先写了向下调用的截止代码,再写调用函数的代码,最后写返回时应该返回什么变量值的代码;除了截止代码,剩下的就是后序遍历,左右中
2、就是在找到p或者q的时候就把,把p和q的值不断向上返回
3、这里的向上返回也要遵循后序遍历的原则,左右中
4、在写中的代码的时候就是会出现上面四种情况,总之,就是不断把p或者是q不断向上返回,直到遇到最近公共祖先,再把公共祖先不断向上返回,最后返回到二叉树的根结点,输出结束。
5、所以整个过程就是在做后序遍历,只不过在后序遍历的时候返回了一些值,p,q,最近公共祖先,这三个变量值在不同的时间被返回了。
6、当遗忘了这个解题逻辑时,可以去看看代码随想录的视频。
7、代码里面的注释也是我的总结(也许不对,但大概率是对的)

Java核心代码:

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        //以下两个if都是向下调用的截止条件
        if(root == null)
            return null;
        if(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;
        else if(left != null && right == null)
            return left;
        else if(left == null && right != null)
            return right;
        else
            return null;
        
    }

Python核心代码:

def lowestCommonAncestor(self, root, p, q):
        """
        :type root: TreeNode
        :type p: TreeNode
        :type q: TreeNode
        :rtype: TreeNode
        """
        if(root == None):
            return None
        if(root == p or root == q):
            return root

        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p, q)

        if(left and right):
            return root
        elif(left and right == None):
            return left
        elif(left == None and right):
            return right
        elif(left == None and right == None):
            return None

C++核心代码:

public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (root == NULL)
            return NULL;
        if (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;
        else if(left != NULL && right == NULL)
            return left;
        else if(left == NULL && right != NULL)
            return right;
        else
            return NULL;
    }

本篇文章为原创,欢迎转载,请注明文章出处链接:https://blog.csdn.net/2301_79084755/article/details/137151039。技术类文章一般都有时效性,本人会不定期对自己的博客进行修正更新,因此请访问出处以查看本文的最新版本。

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值