Amazon Microsoft Interview Question for Software Engineer / Developers






Comment hidden because of low score. Click to expand.
3
of 3 vote

Let h1, h2 be the levels of the two nodes n1, n2 respectively in the tree(find the level by following the parent pointer)
if (h1 > h2) then follow the parent pointer of node n1 move up (h1 - h2) nodes.
else follow the parent pointer of n2 and move up (h2 - h1) nodes.
Now compare both the nodes n1 and n2 and follow the parent pointers until the common ancestor is found.

- Thiyanesh November 19, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Excellent solution!

- Anonymous November 19, 2009 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

I think there must be a way to do so without going to the root, since there is a good chance that one or both nodes are far from the root.

- Anonymous November 19, 2009 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Perfect!

- Aneesha February 28, 2011 | Flag
Comment hidden because of low score. Click to expand.
1
of 1 vote

This is exactly similar problem to "Find the point of intersection of two linked lists". Here the linked lists have the two nodes as heads and the next pointers are the parent pointers all the way to the root.

1. find length of path from node 1 to root via parent ptrs.
2. find length of path from node 2 to root via parent ptrs.
3. In the bigger path traverse difference (mod(len1 - len2)) number of nodes.
4. Traverse one node at a time in both lists till you get common point.

- Anonymous November 29, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
1
of 1 vote

I was asked this same Q..I gave the hash table answer.. then he asked to to optimize it.. he expected

Find out the height of the two nodes in the binary tree. It would take O(n) time. Then, then make one of the pointers to come to the same level as that of the other in the tree. From this point onwards, start traversing the ancestor chain for both the subtrees simultaneously, comparing the parent pointer at each step. The moment the parent pointers come out to be the same, return that parent pointer as the LCA. There are a few edge cases that I am not elaborating here (root being the LCA, straight chain etc), but those can be handled easily.

Analysis: Constant extra space. O(n) worst case runtime.

- Sagar February 23, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

- Traverse to root and store path. O(log n)
- Find first common point in path (which is the LCA). Can do it in O(n) using hash table.

- Anonymous November 15, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

1) Keep the pointer at one of the child's node. Call it current pointer
2) While current-> data lies between child1->data and child2->data, current = current->parent
3) The moment condition #2 fails, you have stepped out of LCA (i.e you moved to LCA's parent). Keep another pointer to remember previous move and return that.

- Anonymous November 16, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

i don't think its a binary search tree.

- Anonymous November 16, 2009 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Then you can try this, not very efficient but still:
1) Take current=<any child>
2) Do tree traversal on current, if you hit the second child, return current as LCA
3) while 2) is false, current=current->parent.

- Anonymous November 17, 2009 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

A slight modification to step 2) above is:
When you start a tree traversal with X as root and you didnt second child you enter the tree to hash and modify tree traversal, so that whenever, you are about to traverse a node, see if is already in hash, then no need to traverse it again as you know second child is not going to be there.
This way the entire run time can be obtained in O(n)

- Anonymous November 17, 2009 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

You can always ask for to confirm. They mean BST when they say *tree*. LCA is specific to the BST.

- banti November 16, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

The question explicitly states that this is not a BST

- abhimanipal April 08, 2010 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

BTNode* FindingCommonAncestor::findCommonAncestor(BTNode* root, BTNode* a, BTNode* b) {
    queue<BTNode*> *q1 = new queue<BTNode*>;
    queue<BTNode*> *q2 = new queue<BTNode*>;

    isDescendent(root, a, q1);
    isDescendent(root, b, q2);

    int sizeA = q1->size();
    int sizeB = q2->size();

    hash_set<BTNode*> set;
    for ( int i = 0; i < sizeA; i++ ) {
        set.insert((BTNode*) q1->front());
        q1->pop();
    }
    
    for  ( int i = 0; i < sizeB; i++ ) {
        BTNode* node = q2->front();
        if ( set.count(node) ) {
            delete q1;
            delete q2;
            return node;
        }
        q2->pop();
    }

    delete q1;
    delete q2;
    return NULL;
}

bool FindingCommonAncestor::isDescendent(BTNode* root, BTNode* node, queue<BTNode*> *q) {
	if ( root == node ) {
		q->push(node);
		return true;
	} else if ( root->left && isDescendent(root->left, node, q) ) {
        q->push(root);
        return true;
    } else if ( root->right && isDescendent(root->right, node, q) ) {
        q->push(root);
        return true;
    }

    return false;
}

- yeo1 November 17, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

You cant traverse tree. only children are pointing to their parents. There is no pointer from parent to child

- Anonymous November 18, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Yeo1 ..Can you please explain your logic?

- gkishan November 18, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

He is basically adding all the parent nodes of, say, first node to a hash table. Next he searches the hash table for parent nodes of the second node. The first match is the common ancestor. I am wondering if there is a more efficient solution. This solution has complexity of O(lg(n)).

- Anonymous November 19, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

this is average case O(lg n).
we need worst case O(lg n).
this can be achieved through RMQ. Yes of course it is the famous LCA problem

- a.p February 08, 2010 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

@a.p: May I ask how to convert it to RMQ? since you can't identify any node of tree by its value, we can't create a cartesian tree.

- tangqiyuan May 13, 2010 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

http://www.careercup.com/question?id=254667&form=comments

- Thiyanesh November 19, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

First we need to have a list of leaf nodes in a queue. Extract node from queue and we move up to its parent and at each stage we compare the parent element with two given node values.If both are greater and if the node is not already visited then we move up to the parent and we mark the parent node as visited. If the parent node value is in between the two given node values then we found our ancestor.If the node is already visited or we reached the root node or both the node values are lesser than the current node when traversing from child to parent then we start the same traversal from the next leaf node.

- karey04 November 19, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

from the two given node, traverse up to the root, when doing so:

1. reverse the child-parent pointer alone the path
2. record the depth of each node
3. then it problem becomes same as the other problem from amazon

- Anonymous November 19, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

this problem is variant of "linked list converge point problem".

the two child nodes are head of the linked list and root is tail. we have to find out the 1st node at which they converge.

So, use the standard method, find length and ...

- Big N November 20, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

I don't think Thiyanesh solution will work......especially when both are at same level.....Just assume when one is at level n on left side of root and other is on level n on right side.............

I think good way to solve it is to traverse one side and put all the pointer in link list in order that we got it and then traverse another list and start comparing it and stop when you found a match. Maximum is that we have to (2logn) moves if lowest common ancestor is a root itself........

Since we have not given the keys also, so I don't think we can do it less than logn......Also, in any case worst case can be less than logn............

- Kunal Gaind November 20, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

BTW, Here is a code if we keys are stored at every node.

If we know the key then we can traverse the elements going towards the parents.

Suppose that n1 and n2 are two nodes and key1 and key2 are values at these nodes respectively.
Step1: Get the largest of two. Now largest value be on right side of common ancestor and smaller value be on left side of common ancestor and both will be on either right side or left side of parent of common ancestor. So, we can use this property to find the common ancestor.

Step2: Start from smaller key and start moving towards root. If value at parent is less than value at current node then it cannot be common ancestor as smaller value lies on left side of common ancestor. So check next node. And if it is greater than node1, then node1 lies on left side of this ancestor of node1 so this ancestor can be a lowest common ancestor. Go to step 3 to check condition on parent of common ancestor.

Step3: For parent of common ancestor, Check that now both node1 and node2 either should lie on left side or on right side. If even one condition is true then you hit the parent node in step2, otherwise go up one step and repeat from step2. Code for it is as follows:

findCommonAncestor( node1, node2)// Assume node 1 is smaller than node2
{
parent = node1->parent;
while(parent)
{
if(parent->key < node1->key)
continue;
else
{
parentParent = parent->parent;

if((parentParent->key < node1->key && parentParent->key < node2->key) || (parentParent->key > node1->key && parentParent->key > node2->key))
return parent;
else
parent=parentParent;
}
}
}

- kunalgaind November 20, 2009 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

I think good way to solve it is to traverse one side till root from one node and put all the pointer in link list in order that we got it and then traverse another list and start comparing it and stop when you found a match. Maximum is that we have to (2logn) moves if lowest common ancestor is a root itself........

If we are not given the keys or tree is not BST, then I don't think we can do it less than logn......Also, in any case worst case it cannot be less than logn............

If we know the key then we can traverse the elements going towards the parents.

Suppose that n1 and n2 are two nodes and key1 and key2 are values at these nodes respectively.
Step1: Get the largest of two. Now largest value be on right side of common ancestor and smaller value be on left side of common ancestor and both will be on either right side or left side of parent of common ancestor. So, we can use this property to find the common ancestor.

Step2: Start from smaller key and start moving towards root. If value at parent is less than value at current node then it cannot be common ancestor as smaller value lies on left side of common ancestor. So check next node. And if it is greater than node1, then node1 lies on left side of this ancestor of node1 so this ancestor can be a lowest common ancestor. Go to step 3 to check condition on parent of common ancestor.

Step3: For parent of common ancestor, Check that now both node1 and node2 either should lie on left side or on right side. If even one condition is true then you hit the parent node in step2, otherwise go up one step and repeat from step2. Code for it is as follows:

findCommonAncestor( node1, node2)// Assume node 1 is smaller than node2
{
parent = node1->parent;
while(parent)
{
if(parent->key < node1->key)
continue;
else
{
parentParent = parent->parent;

if((parentParent->key < node1->key && parentParent->key < node2->key) || (parentParent->key > node1->key && parentParent->key > node2->key))
return parent;
else
parent=parentParent;
}
}
}

- kunalgaind November 20, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

@Kunal
If one of the node is on the left side of the root and other is on the right side of the root, then root will be the LCA as per my above post.

But if the question really meant, "we can't compare two nodes(address)", then i don't have an answer now.("The nodes do not have any key elements or any other data to identify itself." as per the question)

Please do correct if i am missing something.

- Thiyanesh November 20, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

I would prefer to traverse one path fully till root, everytime putting the value in a hash table. now,start traversing for 2nd node and stop as soon as you get the node's value in the hash table.

- t2 November 21, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

2 ways:
1) Traverse to the root, following the parent chain of one node, and preserving each ancestor in a hashtable. In the second pass, traverse up the ancestor chain of the second node, looking for each ancestor of it in the ancestor map of the first node. The first ancestor in the ancestor chain of the second node that appears in the ancestor map of the first node, is the LCA. (same solution as given in the last post)

Not a very efficient process given the need for extra space to store the ancestor chain.

Analysis: O(n) worst case space and time complexity.

2) Find out the height of the two nodes in the binary tree. It would take O(n) time. Then, then make one of the pointers to come to the same level as that of the other in the tree. From this point onwards, start traversing the ancestor chain for both the subtrees simultaneously, comparing the parent pointer at each step. The moment the parent pointers come out to be the same, return that parent pointer as the LCA. There are a few edge cases that I am not elaborating here (root being the LCA, straight chain etc), but those can be handled easily.

Analysis: Constant extra space. O(n) worst case runtime.

- RandomThought November 21, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Finding level of a node takes O(log n) and not O(n) :)

- CyberS1ren November 26, 2009 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

int getLevel(node *ptr)
{
	int level = 0;
	while (ptr)
	{
		level++;
		ptr = ptr->parent;
	}
	return level;
}

node *getCommonAncestor(node *ptr1, node *ptr2)
{
	int h1, h2, diff;
	h1 = getLevel(ptr1);
	h2 = getLevel(ptr2);
	if (h1>h2)
	{
		diff = h1-h2;
		while (diff-- && ptr1)
			ptr1 = ptr1->parent;
	}
	else if (h2>h1)
	{
		diff = h2-h1;
		while (diff-- && ptr2)
			ptr2 = ptr2->parent;
	}
	while (ptr1 && ptr2)
	{
		if (ptr1->parent == ptr2->parent)
			return ptr1->parent;
		ptr1 = ptr1->parent;
		ptr2 = ptr2->parent;
	}
	return NULL;
}

- CyberS1ren November 26, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

find solution in my name

- http://www.topcoder.com/tc?module=Static&d1=tutorials&d2=lowestCommonAncestor#Lowest%20Common%20Ancestor%20%28LCA%29 January 06, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

can be slightly modified the node of tree if yes then i will add a flag to each node
from first pointer move towards it's parent till root
while moving
set the flag value
now start moving from second pointer to it's parent while moving chek the flag value
if it's already set then return that value otherwise keep on moving towards root until u get a node with flag value has been set.

- NaiveCoder February 18, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

typedef struct node_t
{
	node_t* parent;
	node_t* left;
	node_t* right;
} NODE, *PNODE;


PNODE FirstCommonAncestor(PNODE n1, PNODE n2)
{
	int n1Level = GetLevel(n1);
	int n2Level = GetLevel(n2);
	
	while(n1Level < n2Level)
	{
		n1 = n1->parent;
		--n1Level;
	}
	
	while(n2Level < n1Level)
	{
		n2 = n2->parent;
		--n2Level;
	}
	
	while(n1 != n2)
	{
		n1 = n1->parent;
		n2 = n2->parent;
	}
	
	return n1;
}

int GetLevel(PNODE n)
{
	int level = 0;
	while(n->parent)
	{
		n = n->parent;
		++level;
	}
	return level;
}

- Hi March 09, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

i THInk it easy because u have given the parent pointer to each node
wo we can traverse up by chking pointer node
so if at ny time we got same parent it is the answer

CODE:


node* sol(node*ch1,node*ch2)
{
node*k1=ch1;
vector<node*>v1;
while(k1!=NULL)
{
v1.push_back(k1);
k1=k1->parent;
}
vector<node*>v2;
while(k2!=NULL)
{
v2.push_back(k2);
k2=k2->parent;
}
// now traverse form last in both veotrs the last node which is eqal is both is the answer
reverse(v1.begin(),v1.end());
reverse(v2.begin(),v2.end());
for(int i=-1;i<min(v1.size(),v2.size());i++)
{
if(v1[i+1] !=v2[i+1] )return v1[i];
}
}

- coder July 31, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

No specification about extra space so I propose using a stack.

Node* LowestCommonAncestor(Node* node1, Node* node2)
{
  if(!node1 && !node2)
    return null;
    
  if(!node1 || !node2)
    // Ask interviewer what needs to be returned here.
    
  Stack<Node*> s1 = new Stack<Node*>();
  Stack<Node*> s2 = new Stack<Node*>();
  
  Node* temp = node1;
  while(temp)
  {
    s1.push(temp);
    temp = temp->parent;
  }
  
  temp = node2;
  while(temp)
  {
    s2.push(temp);
    temp = temp->parent;
  }
  
  // Nodes from different trees
  if(s1.peek != s2.peek)
    return null;
  
  while(s1.peek == s2.peek)
  {
    temp = s1.pop;
    s2.pop;
  }
  
  return temp;
}

- JSDUDE June 06, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
-1
of 1 vote

famous LCA problem,

with O(NlogN) preprocessing, you can do O(log h) for each LCA query, where h is the max level of tree.

well, but I'm sure the interview is expecting something easier~

- geniusxsy November 15, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

wrong you f*****

- Anonymous July 25, 2010 | Flag
Comment hidden because of low score. Click to expand.
-1
of 1 vote

current=root.
while(current!=NULL){
Do a BFS (or any tree traversal) on left node.(current->left) 
  - if both children are in left node, then now current=root->left. 
  - if left node has only one child, return root as ansector
  - else, current=root->right
}

- Anonymous November 16, 2009 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

probly the worst solution ever .. :)

- Anonymous November 17, 2009 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Really a poor solution

- nagpal_dce August 08, 2010 | Flag


Add a Comment
Name:

Writing Code? Surround your code with {{{ and }}} to preserve whitespace.

Books

is a comprehensive book on getting a job at a top tech company, while focuses on dev interviews and does this for PMs.

Learn More

Videos

CareerCup's interview videos give you a real-life look at technical interviews. In these unscripted videos, watch how other candidates handle tough questions and how the interviewer thinks about their performance.

Learn More

Resume Review

Most engineers make critical mistakes on their resumes -- we can fix your resume with our custom resume review service. And, we use fellow engineers as our resume reviewers, so you can be sure that we "get" what you're saying.

Learn More

Mock Interviews

Our Mock Interviews will be conducted "in character" just like a real interview, and can focus on whatever topics you want. All our interviewers have worked for Microsoft, Google or Amazon, you know you'll get a true-to-life experience.

Learn More