Amazon Interview Question
Applications DevelopersCountry: India
Interview Type: In-Person
some people down vote without no meaning and without even seeing the logic they down vote by thinking that i have down voted their code but don't know some one else would have done it
@vgeek:Why are you so worried about votes?If you have written the code right,right people will definitely praise you for the effort.Don't think about the votes.By the way thanx for pointing out my mistake.
Well good solution @vgeek.I was doing the same but was somewhere stuck around the point about dealing a case where LCA was among the two nodes.
I am not sure whether your approach will work for all the cases, not read the complete code just had a glance seems like you are using array representation of binary tree which will lead to correct answer only in cases binary tree is complete.
And also finding lowest common ancestor can be done without extra space (ignoring recursion stack space) I have pasted the code in my comments.
No it will work for all the cases even if the binary tree is not complete as the code that i have pasted is not a complete binary tree and further I am using an indirect recursion call that is a function calling an another function and there printing the result the same function is not being called again and again so need to worry for stack space.
vgeek as varun pointed out, even if you are not assuming that the binary tree is complete, you would still be using O(n) extra space just to compute the lca. lca for a binary tree can be computed using recursion (o(logn) stack space). I would not write the code here, as you might already know this. My question is, how interesting would this problem be if you can just iterate over the tree once.
We can perform a Breadth First Search, from the node of the tree to any one of the two given nodes (say node1). This can be done in linear O(n) time. Also, we store this path, as an array of node numbers (assuming we number the nodes from 0 (root) to n-1 (last) leaf node), that form the path. (this array is sorted)
We then start moving up (using parents) from the other node (node2), towards the root. Now, while moving, whenever we find a node, that is in the array of node1's path upto root, we stop moving. Now we merge both the paths to get shortest path between them.
main( )
{
...
findpath()
}
findpath(node *a,node *b,node *root)
{
stack s1,s2;
// Get the path of node a from root in a stack
find(a,root,s1);
// Get the path of node b from root in a stack
find(b,root,s2);
//using stack s1,s2 print the path
}
find(a,root,stack s)
{
if(root == a)
{
return 1;
}
if(root == NULL)
{
return 0;
}
s.push(root);
if(find(a,root->left,s) || find(a,root->right,s))
{
return 1;
}
else
{
s.pop( );
return 0;
}
}
Simple:
1. First check whether both the nodes exist in the tree? (skipping for simplicity)
2. Find the lowest common ancestors of both the nodes.
3. Trace path to node1 from LCA node.
4. Trace path from node2 to LCA node.
Let node1.val = val1
and node2.val = val2
node* LowestCommonAncestor(node *ptr, int val1, int val2)
{
if (!ptr)
return NULL;
if (ptr->getData() == val1 || ptr->getData()== val2)
return ptr;
node *left = LowestCommonAncestor(ptr->getLeftChild(), val1, val2);
node *right = LowestCommonAncestor(ptr->getRightChild(), val1, val2);
if (left && right)
return ptr;
if(left)
return left;
else
return right;
}
For tracing path to the node:
LCA = LowestCommonAncestor(root,item1,item2)
trace(LCA,item1);
trace(LCA,item2);
int equal=0;
void trace(node *r,int item)
{
if(equal==1)
return;
if(r->data==item)
equal=1;
if(r!=NULL)
{
trace(r->left,item);
trace(r->right,item);
if(equal==1)
cout<<" "<<r->data;
}
}
I think that your code will not work when for example I enter two node values such that if 8 is a child of node 2 and suppose 6 is a child of node 3 and this node 6 lies in the right subtree of right child of 4 . Then it will return 2 as it will first encounter 8 and then return that node but the least common ancestor of node 8 and 6 would be the parent of node 2 and 3 which is 1.
If I am not wrong, in a tree for any two distinct vertex there exists a unique path simple path.
The question says ''Find the shortest distance b/w any two nodes in a binary tree".
But if there exists only one path then how can shortest path be found(Only if there exists at-least two path then we can speak about Shortest Path).
FYI:
The definition of tree from wiki:
A tree is an undirected simple graph G that satisfies any of the following equivalent conditions:
G is connected and has no cycles.
G has no cycles, and a simple cycle is formed if any edge is added to G.
G is connected, but is not connected if any single edge is removed from G.
G is connected and the 3-vertex complete graph K_3 is not a minor of G.
Any two vertices in G can be connected by a unique simple path.
vgeek ... What is the time complexity of your code ? Is it better than O(n). If so then we can use simply BFS that would give the shortest path in O(n) time
The worst case occurs when the two nodes of the tree lies at the opposite ends that is one node is in the left subtree and the other node is in the right subtree then the number of comparisons required are level-1 where levels the height of the tree. Here we can also apply BFS but its just another technique
int nodeDistance(node *new_node, int n1, int n2){
node *save;
int count = 0, temp = 0;
if(n1 > n2){
temp = n1;
n1 = n2;
n2 = temp;
}
while(n1 < new_node->val && n2 < new_node->val){
new_node = new_node->left;
}
while(n1 > new_node->val && n2 > new_node->val){
new_node = new_node->right;
}
save = new_node;
while(n1 != new_node->val){
if(n1 < new_node->val){
new_node = new_node->left;
count++;
}
else if(n1 > new_node->val){
new_node = new_node->right;
count++;
}
}
new_node = save;
while(n2 != new_node->val){
if(n2 < new_node->val){
new_node = new_node->left;
count++;
}
else if(n2 > new_node->val){
new_node = new_node->right;
count++;
}
}
return count;
}
Just need to find the path from node1 to node 2 throught the LCA of both nodes.
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<string.h>
using namespace std;
struct node {
int data;
struct node *left;
struct node *right;
};
void printPath(int num,struct node *LCA) {
if(num==LCA->data) {
cout<<LCA->data<<" ";
return;
}
struct node *temp=LCA;
if(num<LCA->data)
LCA=LCA->left;
else
LCA=LCA->right;
printPath(num,LCA);
cout<<temp->data<<" ";
}
void findMaxPath(int num1,int num2,struct node *root) {
struct node *num1LCA=root;
struct node *num2LCA=root;
struct node *LCA=root;
while(num1LCA==num2LCA) {
if(num1 < num1LCA->data)
num1LCA=num1LCA->left;
else
num1LCA=num1LCA->right;
if(num2<num2LCA->data)
num2LCA=num2LCA->left;
else
num2LCA=num2LCA->right;
if(num1LCA==num2LCA)
LCA=num1LCA;
}
cout<<"Path from node1 to root\n";
printPath(num1,LCA);
cout<<"\nAnother path starting from node 2 to root\n";
printPath(num2,LCA);
return;
}
// FUNCTION TO INSERT NODES IN THE BINARY TREE
void insertNode(struct node **root,int data) {
// CREATES THE ROOT NODE
if(*root==NULL) {
(*root)=(struct node*)malloc(sizeof(struct node));
(*root)->data=data;
(*root)->left=NULL;
(*root)->right=NULL;
return;
}
// FOR CREATION OF OTHER NODES
if(data < (*root)->data) {
insertNode((&(*root)->left),data);
}
else {
insertNode((&(*root)->right),data);
}
return;
}
// DRIVER FUNCTION
int main() {
struct node *root=NULL;
// TAKES THE INPUT FOR INSERTION
do {
int data;
scanf("%d",&data);
if(data!=-1) {
insertNode(&root,data);
}
else {
break;
}
}while(1);
findMaxPath(10,14,root);
return 0;
}
In order to find the shortest path between any two nodes you have to find the common parent between them that is the least common ancestor.
As it is not a binary search tree so just do a level order traversal and store them in a array then the indexing of the array would be such that for any node of array index n you will have parent at index (n-1)/2 .So for any two nodes just check if they have the same parent. If they have then it is the least common ancestor and the path length is 2 from 1st node to parent and then from parent to second node. If not then iterate upwards until you get a common parent and also increment a path count. I have also uploaded the code for it below.
we can calculate depth of both nodes d1 and d2 which may help us to optimize our code in order to find common parent.
For ex:
case:1 --- if(d1 == d2)
then find the parent node of both nodes and compare in case not same again find parent of parent for both nodes and compare...
case:2 --- if(d1 > d2 && (d1-d2)>1)
then get (d1-d2-1) grand parent of d1 and check whether d2 is parent of d1... if not ....get the parent of (d1-d2) grand parent of d1 and proceed for case :1 [if(d1 == d2)]
case :3 ---- same as case 2
@vgeek
Hi, nice solution! Just one question: Why the indexes helps here? Why not just use hash set?... Thanks.
@Chh.Chiu.19
The indices helps us here because we are doing a level order traversal and it is the property of the binary tree that for any node n we have two children whose indices are: For left child 2*n+1 and for right child 2*n+2 . And also the parent of node n lies at the index (n-1)/2 its floor value. And as we have to find the first common parent of two nodes in this question so this property can be made to work. We can also use hash set but i think that could be complex as it will also do the same work as the array is doing here but no doubt hash set can also be used
In order to find the shortest path between any two nodes you have to find the common parent between them that is the least common ancestor.
As it is not a binary search tree so just do a level order traversal and store them in a array then the indexing of the array would be such that for any node of array index n you will have parent at index (n-1)/2 .So for any two nodes just check if they have the same parent. If they have then it is the least common ancestor and the path length is 2 from 1st node to parent and then from parent to second node. If not then iterate upwards until you get a common parent and also increment a path count. I have also uploaded the code for it below.
This is the code for finding least common ancestor in a binary tree:
a. Store the nodes by doing a normal level order traversal
b. And then find the common parent of the node in the array
- vgeek July 18, 2013