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
Pseudocode:
node *FindCommonAncestor(node *root, node *node1, node *node2) {
node *current = node1;
node_list temp_list;
temp_list.add(current);
while (current != root) {
current = current.parent;
temp_list.add(current);
}
current = node2;
while (current not in temp_list) {
current = current.parent;
}
return current;
}
If the nodes are definitely part of the same tree, then they'll definitely have a common ancestor (even if it's the root in the worst case). So it will always terminate and there's no error condition to worry about.
The first loop runs n times, where n is the depth of node1, so it's O(n). The second loop runs m times, where m in the depth of node2. The lookup into temp list is (at worst) n. So the second loop is O(m*n), and it dominates, so the function runs in O(m*n).
If you use a good set data structure (e.g., a hash table) for the temp space instead of a list, you can cut the lookup to (typically) O(1), without increasing the cost of adding nodes to temp. This reduces our function time to O(m).
The space requirement is O(n) either way.
Since we don't know n and m ahead of time, let's put it in terms of the total number of nodes in the tree: S. If the tree is balanced, then n and m are each bounded by log_2(S), so the run time is O(log_2(S)^2). Log_2 is pretty powerful, so S would have to get pretty big before I'd worry about the power of 2. If the tree is not balanced, then we lose the log_2 (the tree might actually degenerate into a linked list). So the absolute worst case (when one node is the root and the other is the leaf of a completely degenerate tree) is O(S^2).