题目
思路
采用递归的思路假定当前函数一定能找到最近公共祖先的候选者(允许为空)
本质上,该题目有三种情况,情况1:两个节点p,q分布于最深父公共祖先(LCA)的两侧。情况2:两个节点中的较浅节点p就为LCA,此时另一个节点q在该节点之下。情况三:子树中没有p,q,则返回空节点
接下来,我们从自底向上的视角理解。
首先确定返回值。当递归到某个节点,该节点符合(root == p or root == q)的条件就向上返回,这个节点是一个潜在的LCA候选者(Candidate)。候选者的意思是它有可能就是我们在找的LCA,也有可能并不是,但是和None不一样,它是有用的。当递归到None,也向上返回,说明该侧已经搜寻完毕,不可能存在任何候选者。
情况1的对应: 该Candidate向上返回到某个节点Node,发现如果另一侧也返回了一个Candidate。说明Node才是真正的LCA。
情况2的对应:该Candidate向上返回时,一路畅通无阻(另一侧始终是None),一直返回到根节点。说明刚刚的Candidate即为在寻找的LCA。(即p, q都在这一分支上)
情况3的对应:两边都没找到候选者;返回空节点(比如p,q都在右子树;此时访问左子树的时候他就会返回空节点)
代码(26.4.29首刷)
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
if root == nil || root == p || root == q {
return root
}
// 假设左右子树都有公共祖先候选者(若两侧都不为空,则当前根节点即为最近公共祖先;若一侧为空,则p,q都在另一侧;若都为空,则代表没有候选者)
leftLca := lowestCommonAncestor(root.Left, p, q)
rightLca := lowestCommonAncestor(root.Right, p, q)
if leftLca != nil && rightLca != nil {
return root
}
if leftLca != nil {
return leftLca
}
if rightLca != nil {
return rightLca
}
return nil
}
相似题目
思路
这一题相较于上一题;可以通过二叉搜索树的性质;判断p,q与当前节点的大小关系;来确定p,q所处的左右子树。
题目保证p,q一定存在,那就只能三种情况:
- p,q都小于x,返回左子树就行
- p,q都大于x,访问右子树就行
- p, q 在x的两侧,此时直接返回x就行
代码
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
x := root.Val
// 都在左子树上
if p.Val < x && q.Val < x {
return lowestCommonAncestor(root.Left, p, q)
}
// 都在右子树上
if p.Val > x && q.Val > x {
return lowestCommonAncestor(root.Right, p, q)
}
// 左右子树都有; 左右子树都没有的情况不需要讨论; 题目保证一定存在p,q
return root
}

452

被折叠的 条评论
为什么被折叠?



