This question was asked to me in an interview: I have a binary tree and I have to find the common ancestor (parent) given two random nodes of that tree. I am also given a point
Set a pointer at both of the random nodes. Find the depth of each node by traversing to the top and counting the distance from the root node. Then set the pointer at both nodes again. For the deeper node, traverse up until both pointers are at the same depth. Then traverse up for both nodes until the pointers point to the same node. That is the ancestor node.
By "traverse up" I just mean move the pointer to the parent of the current node.
Edit to clarify: The key idea is that when both nodes are at the same depth, you can find the common parent very quickly just by simple traversal. So you climb the lower one until both are at the same depth, and then you traverse up. Sorry I don't really know C or I'd write code, but that algorithm should answer your question.
Edit again: And my method runs in O(log(n)) time and O(1) memory.
Another edit: O(log(n)) in a balanced tree. Worst-case performance is O(n) for an unbalanced tree. Thanks @DaveCahill
I think you could just do a search simultaneously for both nodes; the point at which the search diverges is the common ancestor.
commonAncestor tree a b:
value := <value of node 'tree'>
if (a < value) && (b < value)
then commonAncestor (left tree) a b
else if (a > value) && (b > value)
then commonAncestor (right tree) a b
else tree
Interestingly this approach would scale to more than two nodes (check for all of them to be on the left side of tree
, etc.)
@Above, this will not work, because you are assuming that both nodes are immediate child of some particular node...
8
10 12
7
and I gave the nodes as 7 and 12, answer must be 8. Lets do like this
find(root, d1, d2, n1=null, n2=null)
{
if(n1 && n2) return;
if(!root) return;
else if(root -> d == d1 ) n1 = root;
else if(root -> d == d2 ) n2 = root;
find(root->left, d1, d2, n1, n2);
find(root->right, d1, d2, n1, n2);
}
LCA(root, d1, d2)
{
node *n1=null, *n2=null;
find(root, d1, d2, n1, n2);
if(n1 == null || n2 == null )error 'nodes not present' exit(0);
findIntersect(n1, n2);
}
findInterSect(node *n1, node *n2)
{
l1 = length(n1);
l2 = length(n2);
node *g = n2, *l = n1;
diff = abs(l1 - l2);
if(l1>l2) g = n1 l =n2
while(diff) g = g->parent; diff--;
// now both nodes are at same level
while(g != l) g= g->parent, l = l->parent;
}
Maybe silly approach:
Generate the path from each node to the root, storing it as a string of "L" and "R".
Reverse these strings. Take the longest common prefix - you now have the path to the common ancestor.