题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems
特别鸣谢:来自夸夸群的 醉笑陪公看落花@知乎,王不懂不懂@知乎,QFIUNE@csdn
感谢醉笑陪公看落花@知乎 倾囊相授,感谢小伙伴们督促学习,一起进步
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree
路径法
基本思路:
- 找p的路径
- 找q的路径
- 二者不相等路径遇到的第一个不相等的节点即是最近公共祖先
其中,找路径有两种方法
- 把二叉树转换为数组,根据父节点和左右孩子的下标关系,找所有祖先
- 参考Dijstra算法里面路径存储的想法,初始话一个数组,数组根据下标存父节点的值 参考博文 leetcode 743. 网络延迟时间- 有向图 - 图的一些小知识点 - 迪杰斯特拉(dijkstra)-弗洛伊德(Floyd)
标记法 - 记录每一个节点是不是p,q的公共节点
每个节点有四种情况
- 0:子树中都没有p 或者q
- 1:子树中只有p
- 2:子树中只有q
- 3:子树中同时包含 p和q
节点的情况 = 左子树的情况 + 右子数的情况
一旦某个节点是 3 则说明找到了最近的公共节点
后续遍历+ 递归可以实现
# 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':
def f(root,p,q):
if not root:return 0
r1 = f(root.left,p,q)
if not isinstance(r1,int): return r1
r2 = f(root.right,p,q)
if not isinstance(r2,int): return r2
ans = 1 if root == p else 2 if root == q else 0
r3 = r1+r2 + ans
if r3 == 3:return root
return r1+r2 + ans
return f(root, p, q)
tips:
- not 0: True
- not None: True
路径法和标记法采用深度优先遍历,都是找到结点后返回。
一旦找到,剩下的分支不用再继续遍历了,实现了剪枝
在树中查找 5 和 4 节点、
标记法2 - p q 是否在左右子树中
在树中查找 5 和 4 节点
p q 在树中的存在情况
- p 和 q 在同一个分支上
- p 和 q不在同一个分支上
一旦找到 p q 节点的一个,就不再继续遍历,而是回退去便利其他分支,如果其他分支没有,说明另一个需要查找的节点在已查询到的节点的子树中了。