剑指offer--二叉搜索树的最近公共祖先以及二叉树的最近公共祖先

题目:

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

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

例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]

示例 1:

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


示例 2:

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

说明:

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

思路:首先需要对这个公共祖先节点的概念有一定的了解:对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。

从概念中我们可以知道,最近的公共祖先节点有三种情况,

第一种是pq在root的左右子树上,分别在两边,公共祖先就是root

第二种是p=root,q在p左右子树中p就是公共祖先

第三种是q=root,p在q左右子树中q就是公共祖先

知道了上面的三种情况,还要对二叉树有一定的了解,二叉树左子树全部小于根节点,右子树全部大于根节点,然后我们就可以把我们的条件判断变为三个选一个(根据上面的祖先节点成立的三个条件),三个条件合在一块判断的就是pq在root的两端,pq都在右子树且先找到了其中一个就返回出来,pq都在左子树找到了其中一个就返回出来。

代码:迭代

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        #这一道题可以根据二叉搜索树的特点来进行搜索
        #搜索终止的条件有三个,pq是root的左右子节点,p=root,或者q=root
        while root:
            if root.val<p.val and root.val<q.val:
                root=root.right
            elif root.val>p.val and root.val>q.val:
                root=root.left
            else:break
        return root

递归:

#递归
        if root.val<p.val and root.val<q.val:
            return self.lowestCommonAncestor(root.right,p,q)
        if root.val>p.val and root.val>q.val:
            return self.lowestCommonAncestor(root.left,p,q)
        return root

题目二:

将题目一的搜索树这一条件去掉,变为普通的二叉树。

 

示例 1:

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

思路:满足最近共同祖先的三个条件是相同的,这一道题我们采用递归的方式,引入了left和right来记录递归的结果。跳出递归是root为空的时候,如果我们递归的时候找到了root等于p或者root等于q,那就把它们存储在左子树的递归结果和右子树的递归结果中。

代码:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
        #最近公共祖先的定义是没有变的,还是有三种情况,
        #在root的两侧,p=root,或者q=root
        if not root:return None
        if root==p or root==q:return root#只要找到了左右子树其中的第一个p或者q就可以返回,剩下的再判断
        left=self.lowestCommonAncestor(root.left)#递归左子树找到第一个p或者q,返回回去
        right=self.lowestCommonAncestor(root.right)#同上
        if not left:return right#左子树中没有递归结果,说明都在右子树中,返回遇到的第一个节点p或者q都可以,此时这个节点就是另一个的祖先
        elif not right:return left
        else:return root#上面两种情况都不成立说明p和q是在root的两端的,左右子树都有结果,返回root

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值