image.png

思路1:DFS

  • lowestCommonAncestor函数返回值:若root树中有公共祖先就返回公共祖先,否则返回p / q本身
  • 那么如果左子树为空,说明全部都在右子树上,返回rchild,反之,返回lchild
  • 如果两个子树都不是空的,说明分布在左右两边,返回root

    代码1:

  1. # Definition for a binary tree node.
  2. # class TreeNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.left = None
  6. # self.right = None
  7. class Solution:
  8. # 这里的lowestCommonAncestro函数定义得很暧昧:若root树中有公共祖先就返回祖先,否则返回 p / q 本身
  9. def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
  10. if not root:
  11. return None
  12. if root == p or root == q:
  13. return root
  14. # 以左子树根节点为根节点的树中,p q 的公共节点,若存在公共节点则返回公共节点,否则返回 p / q 本身
  15. lchild = self.lowestCommonAncestor(root.left, p, q)
  16. rchild = self.lowestCommonAncestor(root.right, p, q)
  17. # 如果在左子树和右子树中找到的公共节点都存在:
  18. # 说明两个节点分别在左子树和右子树上
  19. if lchild and rchild:
  20. return root
  21. elif lchild == None:
  22. return rchild
  23. else:
  24. return lchild
  25. return None

思路2:另外一种DFS

  • 题解提供的思路,非常清晰
  • dfs(root, p, q)表示,以root为根节点的子树,是否包含p或者q当中的至少一个,如果是则返回True,否则返回False
  • 两种情况可以确定祖先
    • 如果分别在左右节点上,lchildInclude and rchildInclude同时成立
    • 一者是根节点,同时另外一者在其左子树或者右子树上

      代码2:

  1. # Definition for a binary tree node.
  2. # class TreeNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.left = None
  6. # self.right = None
  7. class Solution:
  8. def __init__(self):
  9. self.ancestor: TreeNode() = None
  10. # root子树中是否含有p 和 q 两个节点中至少一个
  11. def dfs(self, root: TreeNode(), p: TreeNode(), q: TreeNode()) -> bool:
  12. if not root:
  13. return False
  14. lchildInclude = self.dfs(root.left, p, q)
  15. rchildInclude = self.dfs(root.right, p, q)
  16. # 第一种情况:分别在左右节点上
  17. if lchildInclude and rchildInclude:
  18. self.ancestor = root
  19. # 第二种情况:某一个是根节点
  20. if (root == p) and (lchildInclude or rchildInclude):
  21. self.ancestor = root
  22. elif (root == q) and (lchildInclude or rchildInclude):
  23. self.ancestor = root
  24. return lchildInclude or rchildInclude or root == p or root == q
  25. def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
  26. self.dfs(root, p, q)
  27. return self.ancestor

思路3:DFS + 建立爸爸表

  • 树结构的问题中,建立爸爸表是一件很重要的事情
  • 所谓爸爸表,就是一个字典,其记录了每个节点的父亲是谁fa[node] = oldNode表示node节点的爸爸是oldNode
  • 可以通过DFS的方式去建立爸爸表,然后孩子节点从下往上找爸爸,找到的位置通过vis字典去标记,第二个孩子往上走的时候,如果vis字典中已经有相关记录了,那么就说明这是一个公共祖先。
  • 此方法应该是此题最最直观的想法了。

    代码3:

  1. # Definition for a binary tree node.
  2. # class TreeNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.left = None
  6. # self.right = None
  7. class Solution:
  8. def __init__(self):
  9. self.ancestor: TreeNode() = None
  10. self.fa = dict()
  11. self.vis = set()
  12. def dfs(self, root: TreeNode()) -> None:
  13. if not root:
  14. return
  15. if root.left:
  16. self.fa[root.left] = root
  17. self.dfs(root.left)
  18. if root.right:
  19. self.fa[root.right] = root
  20. self.dfs(root.right)
  21. def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
  22. # 建立爸爸表
  23. self.dfs(root)
  24. self.fa[root] = None
  25. # 叶子节点从下往上遍历
  26. while p != None:
  27. self.vis.add(p)
  28. p = self.fa[p]
  29. while q != None:
  30. if q in self.vis:
  31. return q
  32. q = self.fa[q]
  33. return root