【leetcode-Python】-后序遍历+回溯-236. Lowest Common Ancestor of a Binary Tree

题目链接

https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/

题目描述

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

树中所有节点的值都唯一,p、q为不同节点且均存在于给定的二叉树中。

示例

输入:root = [3,5,1,6,2,0,8,null,null,7,4],p=5,q = 1

输出:3

节点1和节点5的最近公共祖先是节点3。

解题思路

对于二叉树问题,逃不开二叉树的前序、中序、后序遍历这三种递归顺序。对于这道题,两个指定节点p和q的最近公共祖先nearest有三种情况:
(1)p在nearest的左子树中,q在nearest的右子树中。或者p在nearest的右子树中,q在nearest的左子树中。

(2)q在p的子树中,此时nearest = p。

(3)p在q的子树中,此时nearest = q。

因此我们很容易想到,要先不断向下递归在二叉树中找到p和q,再向上回溯找p和q的最近公共祖先。因此我们设计一个递归函数,这个递归函数的参数为(root,p,q):

(1)如果以root为根节点的子树中既有p,又有q,就返回p和q的最近公共祖先。

(2)如果以root为根节点的子树中只有p,那么就返回p;如果以root为根节点的子树中只有q,那么就返回q。(如果以root为根节点的子树中只有p或q一个元素,那么就返回p或q的最近祖先,即p或q本身。)

(3)如果以root为根节点的子树中既没有p也没有q,此时返回None。(相当于剪枝)

首先我们要定义递归的终点:如果root为None,说明递归到了最后一层,此时返回root(None)即可;如果root为p,此时就返回p。如果root为q,就返回q。

由于我们的搜索方向是先自上而下找p和q,每次递归搜索root左子树和root右子树,然后再往上回溯判断当前节点是否是p和q的最近公共祖先(根据左子树和右子树的递归结果判断)。因此我们要采用后序遍历的顺序。

举例说明算法步骤:

 

 

 

Python实现

在下面的代码中,如果p和q分别位于root的两个子树中(比如p在root的左子树中,q在root的右子树中),那么left就等于p(递归到root == p的时候将p不断向上返回),right就等于q(递归到root ==q时将q不断向上返回)。我们将root返回,因为在后序遍历+回溯过程中第一个满足left==p且right==q条件的节点一定是最近公共祖先。

如果p和q都不存在root的两个子树中,此时left == None,right== None,最后返回None。

如果p和q都只存在于root的左子树中,此时如果p比q高,那么下一层递归返回的left为p,right为None(递归找到p就会返回,不会再往下找q。因为如果q在p的子树中,其他子树如当前层的root.right一定不含有q,只会返回None)。当前层递归返回left。

如果p和q都只存在于root的右子树中,此时如果p比q高,那么下一层递归返回的right为p,left为None。当前层递归返回right。

如果root的子树中只存在p,假设p存在于root的左子树中,右子树中不存在q(由于节点唯一,已知p在root的左子树中,p一定不会出现在root的右子树中),那么left就等于p,right等于None,当前层的递归就返回left。

root的子树中只存在q是类似的情况。

def lowestCommonAncester(self,root,p,q):
    #递归终止条件判断:root为None时、root为p时、root为q时
    if(root == None or root == p or root == q):
        return root
    #递归左子树,找p、q的最近公共祖先(如果存在),或p的最近祖先(如果左子树中只存在p,则返回p)或q的最近祖先(如果左子树中只存在q,则返回q)
    left = self.lowestCommonAncester(root.left,p,q)
    #递归右子树,找p、q的最近公共祖先(如果存在),或p的最近祖先(如果右子树中只存在p,则返回p)或q的最近祖先(如果右子树中只存在q,则返回q)
    right = self.lowestCommonAncester(root.right,p,q)
    
    #在这里对递归返回的left和right做处理
    #如果left不为空,right不为空,说明p和q分别处于root的两个子树中,由于是后序遍历,第一个满足这个条件的root就是最近公共祖先,我们把这个节点往回传。
    if(left and right):
        return root
    
    #如果right为空,left不为空。说明root的右子树中既没有p也没有q,左子树中可能既有p也有q,可能只有p,可能只有q。left有可能是最近公共祖先
    if not right and left:
        return left
    if not left and right:
        return right
    

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值