题目地址:
https://www.lintcode.com/problem/lowest-common-ancestor-ii/description
给定一个二叉树,求两个节点 A A A和 B B B的最近公共祖先。题目保证两个节点都属于这棵二叉树,同时每个节点有一个指向其parent的指针。
由树的性质知,唯一存在从树根到 A A A和 B B B的路径。设树根为 r r r, r r r到 A A A的路径为 r = A 0 → A 1 → A 2 → . . . → A r=A_0\to A_1\to A_2\to ...\to A r=A0→A1→A2→...→A,设 r r r到 B B B的路径为 r = B 0 → B 1 → B 2 → . . . → B r=B_0\to B_1\to B_2\to ...\to B r=B0→B1→B2→...→B,那么由于 r = A 0 = B 0 r=A_0=B_0 r=A0=B0,显然存在某个 k k k使得 A k − 1 = B k − 1 A_{k-1}=B_{k-1} Ak−1=Bk−1但 ∀ l ≥ k \forall l\ge k ∀l≥k,有 A l ≠ B l A_l\ne B_l Al=Bl(或者一条路径完全包含在另一条路径里)。理由是,因为树没有环,所以一旦两条路径开始分叉,就永远不会再相遇了。即 A k − 1 A_{k-1} Ak−1就是 A A A和 B B B的最近公共祖先。所以我们的算法是,先求出两个节点的深度,让深的那个向上走,一直到两者一样深,再一起向上走,直到相等为止。代码如下:
public class Solution {
/*
* @param root: The root of the tree
* @param A: node in the tree
* @param B: node in the tree
* @return: The lowest common ancestor of A and B
*/
public ParentTreeNode lowestCommonAncestorII(ParentTreeNode root, ParentTreeNode A, ParentTreeNode B) {
// write your code here
int dA = depth(root, A);
int dB = depth(root, B);
if (dA > dB) {
while (dA != dB) {
A = A.parent;
dA--;
}
} else {
while (dA != dB) {
B = B.parent;
dB--;
}
}
while (A != B) {
A = A.parent;
B = B.parent;
}
return A;
}
private int depth(ParentTreeNode root, ParentTreeNode node) {
int res = 0;
while (root != node) {
node = node.parent;
res++;
}
return res;
}
}
class ParentTreeNode {
public ParentTreeNode parent, left, right;
}
时间复杂度 O ( h ) O(h) O(h)。