## Lowest Common Ancestor of a Binary Tree Part II

July 21, 2011 in binary tree

Given a binary tree, find the lowest common ancestor of two given nodes in the tree. Each node contains a parent pointer which links to its parent.

**Note:**

This is Part II of Lowest Common Ancestor of a Binary Tree. If you need to find the lowest common ancestor without parent pointers, please read Lowest Common Ancestor of a Binary Tree Part I.

_______3______ / \ ___5__ ___1__ / \ / \ 6 _2 0 8 / \ 7 4

If you are not so sure about the definition of lowest common ancestor (LCA), please refer to my previous post: Lowest Common Ancestor of a Binary Search Tree (BST) or the definition of LCA here. Using the tree above as an example, the LCA of nodes 5 and 1 is 3. Please note that LCA for nodes 5 and 4 is 5.

In my last post: Lowest Common Ancestor of a Binary Tree Part I, we have devised a recursive solution which finds the LCA in O(*n*) time. If each node has a pointer that link to its parent, could we devise a better solution?

**Hint:**

No recursion is needed. There is an easy solution which uses extra space. Could you eliminate the need of extra space?

**An easy solution:**

As we trace the two paths from both nodes up to the root, eventually it will merge into one single path. The LCA is the exact first intersection node where both paths merged into a single path. An easy solution is to use a hash table which records visited nodes as we trace both paths up to the root. Once we reached the first node which is already marked as visited, we immediately return that node as the LCA.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | Node *LCA(Node *root, Node *p, Node *q) { hash_set<Node *> visited; while (p || q) { if (p) { if (!visited.insert(p).second) return p; // insert p failed (p exists in the table) p = p->parent; } if (q) { if (!visited.insert(q).second) return q; // insert q failed (q exists in the table) q = q->parent; } } return NULL; } |

The run time complexity of this approach is O(*h*), where *h* is the tree’s height. The space complexity is also O(*h*), since it can mark at most 2*h* nodes.

**The best solution: **A little creativity is needed here. Since we have the parent pointer, we could easily get the distance (height) of both nodes from the root. Once we knew both heights, we could subtract from one another and get the height’s difference (

*dh*). If you observe carefully from the previous solution, the node which is closer to the root is always

*dh*steps ahead of the deeper node. We could eliminate the need of marking visited nodes altogether. Why?

The reason is simple, if we advance the deeper node *dh* steps above, both nodes would be at the same depth. Then, we advance both nodes one level at a time. They would then eventually intersect at one node, which is the LCA of both nodes. If not, one of the node would eventually reach NULL (root’s parent), which we conclude that both nodes are not in the same tree. However, that part of code shouldn’t be reached, since the problem statement assumed that both nodes are in the same tree.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | int getHeight(Node *p) { int height = 0; while (p) { height++; p = p->parent; } return height; } // As root->parent is NULL, we don't need to pass root in. Node *LCA(Node *p, Node *q) { int h1 = getHeight(p); int h2 = getHeight(q); // swap both nodes in case p is deeper than q. if (h1 > h2) { swap(h1, h2); swap(p, q); } // invariant: h1 <= h2. int dh = h2 - h1; for (int h = 0; h < dh; h++) q = q->parent; while (p && q) { if (p == q) return p; p = p->parent; q = q->parent; } return NULL; // p and q are not in the same tree } |

**Further Thoughts**:

Isn’t the solution above neat? It requires some creative thought and is quite subtle.

A variation of this problem which seemed to be more popular is:

Given two singly linked lists and they both intersect at one point (ie, forming a Y shaped list). Find where the two linked lists merge.

I am sure you know how to answer this question now

Lowest Common Ancestor of a Binary Tree Part II,
Pankaj said on July 22, 2011

Please try to remove add if possible.

Instead add a paypal option so that those who get benefit from your blog can support this hard work of yours

-7maxq said on July 23, 2011

There seems to be a bug in your code?

Please see below.

Node *LCA(Node *root, Node *p, Node *q) {

hash_set visited;

while (p || q) {

if (p) {

if (!visited.insert(p).second)

return p; // insert p failed (p exists in the table)

p = p->parent;

}

if (q) {

if (!visited.insert(p).second) parent;

}

}

return NULL;

+11337c0d3r said on July 23, 2011

Are you saying that on line 10:

(!visited.insert(p).second)

should be:

(!visited.insert(q).second)

If that is, this is a mistake and thanks for pointing that out. I will correct the post later.

0protocol said on February 20, 2012

What is “second” in (!visited.insert(q).second) ?

I know in Java, for “visited.add(q)”, if q exists, it will return false. But here, what is the mean of “second” ?

01337c0d3r said on February 20, 2012

The insert() function returns a pair.

The insert member function returns a pair whose bool component returns true if an insertion was make and false if the hash_set already contained an element whose key had an equivalent value in the ordering

http://msdn.microsoft.com/en-us/library/2t5cf4t8%28v=vs.80%29.aspx

0Chetan Sharma said on July 25, 2011

Various solution to the Y shaped linked list problem exists, one of them being:

Start traversing first list setting the next pointer to NULL in the process. Now start traversing the second list until the next pointer of a node is not NULL. At this point the current node is the intersecting node. Though this solution requires modification to the list but is more efficient as you need to traverse the list only once

-1fangstar said on November 8, 2011

For the Y shaped linked list problem, instead of difference in height we need to calculate the difference in length between the linked lists right?

Then do the similar advancement on the longer length, and then iterate for a match?

TIY

0Eugene Kirpichov said on March 28, 2012

The solution is indeed neat, but I would not call it “best” in all situations. It requires at least traversing both nodes to the root, whereas the “easy” solution may stop much earlier than that.

+3景泰蓝 said on April 5, 2012

Node *LCA(Node *root, Node *p, Node *q){

Node * q_path[MAX] , p_path[MAX];

int qi=0, pi=0;

while(q) { q_path[qi++]=q; q=q->parent ;}

while(p) { p_path[pi++]}=p; p=p->parent; }

while(qi>=0 && pi>=0){ if(q_path[--qi] != p_path[--pi]) return p_path[qi] ; }

return NULL;

}

0alexlee said on January 28, 2015

your code “while(qi>=0 && pi>=0){ if(q_path[--qi] != p_path[--pi]) return p_path[qi] ; }”has a question,I think should return p_path[qi+1];

0Raja said on June 2, 2012

The LCA of 6 and 2 in the example should be 5 or 3 ? Since its lowest common ancestor – Shouldnt it be 3 ?

But the code given would give us 5 as the answer. Please clarify ?

Thanks,

Raja.

-1Ganesh R said on July 27, 2012

You are using parent.. But the actual structure of a Binary tree should be

struct tree

{

struct tree *lchild;

struct tree *rchild;

int element;

};

If additional varialbles or terms added, can it called a Binary tree???

-1George said on August 12, 2012

Yes, a binary tree doesn’t stop being a binary tree if you add a pointer to the parent node. The solution provided is indeed very creative

+1Sumit said on May 26, 2013

@ Ganesh , I think it should be , for node structure can be modified , yet the overall structure doesn’t cease to be a binary tree , I know I had applied the exactly same approach when asked to find LCA in Univ Exams , only to score a zero for not following the soln they had in the answer key ! Damn !!

we may avoid swapping by using minptr=minheight(h1,h2) and then proceed as is

0Daniel said on August 19, 2012

There is a better solution…

The suggested solution is o(depth of tree), there is a solution in o(distance of two nodes).

1.Note: Once you find a common ancestor, you can find the differences between the two nodes heights, and find the lowest common ancestor.

2. In order to find a common ancesstor in o(distance) you can walk up in the tree alternately with each pointer in the following way:

a. first you will go with the first pointer 1 step.

b. with the second pointer 2 steps.

c. with the first pointer 4 steps.. etc

where in each step you compare the pointers, and you stop once they are equal.

On the iteration where the number of steps is >= distance of the two nodes, you will find some common ancestor o(distance).

0Tong Liu said on December 30, 2012

it is like another question finding intersection of two linked list

0Raj said on January 21, 2013

COuld you please explain it.I did not understand How do we go back like p=p->parents.

0Partha Pratim Sirker said on January 22, 2013

Although it is similar to a Y shaped linkedlist problem, the solution would involve find out the path of the nodes separately which is of O(n) operation. So in total we will do two iteration of O(n) and then O(log n) to find out the Y junction. (Assuming there is no parent pointer). I found this solution better where there is only one iteration and it is of O(n) complexity. It is done with a single post-order traversal. http://www.dsalgo.com/LowestCommonAncestor.php

0pavi said on February 22, 2013

The solution given in the link you provided and what you are talking about is similar (or exactly same) to the one given in the part 1 of this Article.

Here’s the link:

http://leetcode.com/2011/07/lowest-common-ancestor-of-a-binary-tree-part-i.html

0Prateek Caire said on February 24, 2013

How about this one.Move one of the nodes up and delink the parent by putting null to parent pointer.Move second node up till we do not find delinked parent. That node is LCA. Solution, however, alters tree structure

0DaShan said on March 17, 2013

I don’t think computing the nodes’ heights is necessary:

-Assuming we store the “root-to-node” path in a stack

-Then going down to child node is represented by a stack “push”, and a backtrack is achieved by a stack pop

-(1) After finding the 1st node, we have a stack that stores the path from the root to the 1st node

-(2) Then we continue the traversal, by “pop”, “push”, “push”, …, until reaching the 2nd node

-between (1) and (2), a prefix of the stack, namely from the root to the LCA, will not change

-therefore, we can use a “watermark pointer” to maintain “the lowest element of the stack content at (1) that survives till (2) is done”.

-Once (2) is done, the above “watermark pointer” points to the LCA.

0Siyong said on March 21, 2013

That would require extra memory.

0Chris Tsang said on February 21, 2014

Why return NULL when p and q is both Null? To handle the situation when p and q is not in the same tree?

0hypnotize said on July 22, 2014

If some one needs to be updated with hottest technologies

then he must be pay a quick visit this web site and be up to date everyday.

0