二叉树的最近公共祖先

236. 二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

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

示例 1:

 

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1输出:3解释:节点 5 和节点 1 的最近公共祖先是节点 3 。

示例 2:

 

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4输出:5解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。

示例 3:

输入:root = [1,2], p = 1, q = 2输出:1

思路:

  这一题我们就用递归来做。定义寻找公共祖先函数 lowestCommonAncestor,我们已知它的功能很明确:传入根节点root和两个节点p和q,返回这两个节点的最小公共祖先。

  直接说思路吧:我们从最外层的视角审视这个递归,传入的是根节点、结点p、结点q,假设节点p和节点q分别在根节点的左右两处,那么根节点就是两者的最小公共祖先;假设p和q都在根节点的左子树,则我们送入递归(根节点的左子树,节点p,节点q)就好了,让它更进一步;假设p和q都在根节点的右子树,则我们送入递归(根节点的右子树,节点p,节点q);假设根节点下既没有q也没有q,则肯定不合理,返回None。

  但是还有一种情况我们没有考虑到,我们把它作为base case。这种情况是:假设根节点下只有q或只有p,则这个节点在哪个子树,就更进一步送入递归。比如只有根节点的右子树有个q,则送入递归(根节点的右子树,节点p,节点q)即可。因为这种情况下,我们是找不到p和q的公共祖先的,我们只需要最后把根节点逼近到它包含的p或q节点,然后返回这个根节点即可。所以针对这种情况还有一个base case:假设根节点等于p或q,直接返回当前根节点。Base case部分也就定义好了。

  虽然具体逻辑和base case可以讲得很明白,但是代码里巧妙地将这些思路进行了一个整合,所以上面的思路大概理解即可,不要逐一去对照代码来看,代码写得更加简洁:

代码:

class Solution(object):

    def lowestCommonAncestor(self, root, p, q):

        if not root:#处理一下特殊情况之类的

            return

        if root==p or root==q:#base case,如果root等于p或q了

            return root#直接返回当前root

        left_res = self.lowestCommonAncestor(root.left,p,q)#递归去寻找root.left

        right_res = self.lowestCommonAncestor(root.right,p,q)#递归root.right

        if left_res and right_res:#假如左右两边都有,则root就是公共祖先

            return root

        if left_res:#假如只有左边有——不管是“左边有p和q”还是“左边有p或q”

            return left_res#交给root.left的递归即可

        if right_res:#假如只有右边有,同理

            return right_res

        return None#假如左右两边都找不到,则返回None

小结:

  虽然我们可以把具体情况罗列得很详细分明,但实际的代码还是把部分功能糅杂在一起了,所以看起来不是清晰,但知道思路之后,应该也感觉到这样写的巧妙之处吧。

  最后感觉再梳理一下我们处理的情况和思路:

  1. 假如root的左边包含q,右边包含q;或者左边包含q,右边包含p,即一边一个,则直接返回root。这种情况没问题吧,也就是我们唯一找到目标节点的情况。
  2. 假如root下既不包含p也不包含q,则返回None。
  3. 假设root左子树同时包含p和q,则返回root.left的递归。
  4. 假设root的右子树同时包含p和q,则返回root.right的递归。
  5. 假如root下只包含p(不管左还是右),则送入root.left或root.right的递归,最终通过递归到情况7返回p节点。
  6. 假如root下只包含q(不管左还是右),则送入root.left或root.right的递归,最终通过递归到情况7则返回q节点。
  7. 假设root等于q或p,直接返回root。
posted @   JunanP  阅读(5)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示