题目地址:
https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/
寻找一棵二叉树某两个节点p和q的最近公共祖先。
先证:w是p与q的最近公共祖先,当且仅当w=p且q是p的后代(或者反之),或者p与q分别在w的左右子树之中。
先证充分性:若p与q分别位于w的左右子树中,那么很显然w是公共祖先,并且w的左右子树根都不是公共祖先,这说明了w的“最近”性质。证毕。
再证必要性:反证法。不妨设p与q都位于w的左子树中,那么w的左子树根是更近的公共祖先,与w的“最近”性质矛盾。证毕。
所以只需要找到一个p和q分别位于它左右子树的那个节点就行了。为此我们需要在root的左右两个子树中搜索p和q,如果一边搜索出p另一边搜索出q返回即可。代码如下:
public class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) {
return root;
}
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left != null && right != null) {
return root;
} else if (left == null) {
return right;
} else {
return left;
}
}
}
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int x) {
val = x;
}
}
时间复杂度O(n),空间O(h)。
算法正确性证明:
需要证明这个函数,若以root为树根的树中存在p与q,则会返回其最近公共祖先,若只存在p或q,则对应地返回p或q,否则会返回null。
如果root是p或者q显然正确。如果树的节点数为0,1,2或3时显然正确;假设树的节点数是k的时候也正确,如果树的节点数是k+1,那么其左右子树节点数必然小于等于k,据数学归纳法,若left与right里分别有p和q,那说明p和q在root的两端,那就返回root。否则按照数学归纳法,就返回了正确答案。证毕。