系列题目
236. 二叉树的最近公共祖先
1676. 二叉树的最近公共祖先IV
1644. 二叉树的最近公共祖先 II
235. 二叉搜索树的最近公共祖先
1650. 二叉树的最近公共祖先 III
class LowestCommonAncestor:
"""
236. 二叉树的最近公共祖先
题目强调p和q一定存在于二叉树中,区别于1644题
https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/
"""
def solution(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
def find(root, val1, val2):
if not root:
return None
# 这里对应情况二
if root.val == val1 or root.val == val2:
return root
left = find(root.left, val1, val2)
right = find(root.right, val1, val2)
# 这里对应情况一, 【后序位置,已经知道左右子树是否存在目标值】
if left and right:
# 当前节点是 LCA 节点
return root
return left if left else right
return find(root, p.val, q.val)
class LowestCommonAncestor2:
"""
1676. 二叉树的最近公共祖先IV
这道题把p和q换成了包含若干个节点的列表,
同样这些列表里的所有节点一定存在于二叉树中,区别于1644题
https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree-iv/
"""
def solution(self, root: 'TreeNode', nodes: List[TreeNode]) -> 'TreeNode':
# 将列表转化成哈希集合,便于判断元素是否存在
values = set()
for node in nodes:
values.add(node.value)
self.find(root, values)
def find(self, root: 'TreeNode', values):
if not root:
return None
# 前序位置
if root.value in values:
return root
left = self.find(root.left, values)
right = self.find(root.right, values)
# 后序位置,已经知道左右子树是否存在目标值
if left and right:
return root
return left if left else right
class LowestCommonAncestor3:
"""
1644. 二叉树的最近公共祖先 II
输入一棵不含重复值的二叉树的,以及两个节点 p 和 q,
这道题区别于236题,给定的两个节点p和q不一定存在于树中,
不存在返回空指针,存在则返回最近公共祖先节点
https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree-ii/
"""
def __init__(self):
# 用于记录p和q是否存在于二叉树中
self.foundP = False
self.foundQ = False
def solution(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
res = self.find(root, p.val, q.val)
if not self.foundP or not self.foundQ:
return None
return res
def find(self, root, val1, val2):
"""
在二叉树中寻找 val1 和 val2 的最近公共祖先节点
:param root:
:param val1:
:param val2:
:return:
"""
if not root:
return None
left = self.find(root.left, val1, val2)
right = self.find(root.right, val1, val2)
# 后续位置,判断当前节点是不是LCA
if left and right:
# 当前节点是 LCA 节点
return root
# 后续位置,判断当前节点是不是目标值
if root.value == val1 or root.value == val2:
if root.value == val1:
self.foundP = True
if root.value == val2:
self.foundQ = True
return root
return left if left else right
class LowestCommonAncestor4:
"""
235. 二叉搜索树的最近公共祖先
这是一颗BST树,要充分利用 左子节点 < 父节点 < 右子节点 的大小关系寻找LCA
https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/
"""
def solution(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
val1 = min(p.val, q.val)
val2 = max(p.val, q.val)
return self.find(root, val1, val2)
# 在 BST 中寻找 val1 和 val2 的最近公共祖先节点
def find(self, root, val1, val2):
if not root:
return None
if root.val > val2:
return self.find(root.left, val1, val2)
elif root.val < val1:
return self.find(root.right, val1, val2)
else: # val1 <= root.val <= val2
return root
class LowestCommonAncestor5:
"""
1650. 二叉树的最近公共祖先 III
这道题,给出的二叉树节点比较特殊,包括指向父节点的指针,
和寻找两个单链表的相交的起始点做法一样【160. 相交链表】
二叉树的最近公共祖先 III
https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree-iii/
"""
class Node:
def __init__(self):
self.val = None
self.left = None
self.right = None
self.parent = None
def solution(self, p: 'Node', q: 'Node') -> 'Node':
# 链表双指针技巧
a, b = p, q
while a != b:
# a 走一步,如果走到根节点,转到 q 节点
if not a:
a = q
else:
a = a.parent
# b 走一步,如果走到根节点,转到 p 节点
if not b:
b = p
else:
b = b.parent
return a