LeetCode 236. Lowest Common Ancestor of a Binary Tree 详细题解

一:题意

给定一颗二叉树,两个节点p和q,求出节点p和节点q的最低公共祖先。
最先公共祖先的定义是:The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself)
在这里插入图片描述
如图所示:1和5的公共祖先是3, 0和4的公共祖先是3, 4和5的公共祖先是5。。。

二:思路

(1)如果这棵树是排序二叉树,则先序遍历,对于每一个根节点,如果满足根节点的值的大小在节点p和节点q的值之间,则这个根节点就是最低公共祖先。
(2)如果每个节点的定义中出现了指向父节点的指针,则从节点p和节点q出发,沿着父指针向根节点遍历,得到两个链表,从而变成求两个链表的第一个公共节点。
(3)如果是普通的二叉树,则可以从第二种情况中受到启发,也就是Path Sum中的思想,深度优先搜索这棵树,当一条路径的末尾是节点p或节点q时,记录下这条路径,然后最终获得两条路径分别是从根节点到节点p,或从根节点到节点q,再求两个链表中最后一个公共节点。

三:举例说明与代码实现

方法一:Path Sum 中的记录路径的思路

例1:如上图所示
p = 2, q = 8
则两条路径分别为[3,5,2], [3,1,8],此时两条路径的最后一个公共节点就是节点3

例二:
p = 4, q = 5
则两条路径分别为[3,5,2,4], [3,5],此时两条路径的最后一个公共节点就是节点5

python实现为:

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

    if not root or not p or not q: return None
   
     def dfs(root, p, q, path):
         path.append(root)  # 返回的是节点
         # print(path)
         # if not root.left and not root.right: return
         if path[-1] == p or path[-1] == q:
             self.ans.append(path[:])  # 这里一定得切片
         if root.left:
             dfs(root.left, p, q, path)
         if root.right:
             dfs(root.right, p, q, path)
         path.pop()
     
     self.ans = []
     
     dfs(root, p, q, [])   # 获取了两条路径
     
     leni = len(self.ans[0])
     lenj = len(self.ans[1])
     
     i = 0
     res = 0
     while i < min(leni,lenj):
         if self.ans[0][i] == self.ans[1][i]:   # 球最后一个公共节点
             res = self.ans[0][i]
         i += 1
     
     return res

方法二:使用父指针

思路:遍历二叉树时记录下节点的父节点,当遍历到节点p或节点q时,可以回溯到他们的最低公共祖先.

算法步骤:

python:

# Stack for tree traversal
        stack = [root]

        # Dictionary for parent pointers
        parent = {root: None}

        # Iterate until we find both the nodes p and q
        while p not in parent or q not in parent:   # 记录父节点

            node = stack.pop()

            # While traversing the tree, keep saving the parent pointers.
            if node.left:  # 层次遍历
                parent[node.left] = node  # key=子节点,value=父节点
                stack.append(node.left)
            if node.right:
                parent[node.right] = node
                stack.append(node.right)

		# 开始回溯找最低公共祖先
        # Ancestors set() for node p.
        ancestors = set()
        # Process all ancestors for node p using parent pointers.
        while p:
            ancestors.add(p)
            p = parent[p]

        # The first ancestor of q which appears in
        # p's ancestor set() is their lowest common ancestor.
        while q not in ancestors:
            q = parent[q]
            
        return q
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值