Given the root of a Binary Tree with unique values and two node values n1 and n2, find the Lowest Common Ancestor (LCA). LCA is the deepest node that has both n1 and n2 as descendants.
Note: Both node values are always present in the Binary Tree.
Examples:
Input: root = [1, 2, 3, N, N, 6, 7, 8], n1 = 7, n2 = 8
[Naive Approach] Checking Each Node as LCA - O(n^2) Time and O(h) space
The idea is to consider every node as a potential Lowest Common Ancestor (LCA). For each node, check whether n1 and n2 are present in its subtree. The deepest node whose subtree contains both nodes is the LCA.
Working of the Approach:
Start from the root and consider the current node as a potential LCA.
Search its subtree to check whether n1 is present.
Search its subtree again to check whether n2 is present.
If both nodes are present, consider the current node as an LCA.
Continue for all nodes and keep the deepest valid LCA.
Return the deepest node found as the LCA.
C++
#include<bits/stdc++.h>usingnamespacestd;classNode{public:intdata;Node*left;Node*right;Node(intvalue){data=value;left=right=nullptr;}};boolhasNode(Node*root,intvalue){if(root==nullptr)returnfalse;returnroot->data==value||hasNode(root->left,value)||hasNode(root->right,value);}voidfindLca(Node*root,intn1,intn2,Node*&ans,intdepth,int&bestDepth){if(root==nullptr)return;// Check the current node as a potential LCA.if(hasNode(root,n1)&&hasNode(root,n2)){if(depth>bestDepth){bestDepth=depth;ans=root;}}// Continue checking every node as a potential LCA.findLca(root->left,n1,n2,ans,depth+1,bestDepth);findLca(root->right,n1,n2,ans,depth+1,bestDepth);}Node*lca(Node*root,intn1,intn2){Node*ans=nullptr;intbestDepth=-1;findLca(root,n1,n2,ans,0,bestDepth);returnans;}intmain(){Node*root=newNode(1);root->left=newNode(2);root->right=newNode(3);root->right->left=newNode(6);root->right->right=newNode(7);root->right->left->left=newNode(8);intn1=7;intn2=8;cout<<lca(root,n1,n2)->data<<endl;return0;}
C
#include<stdio.h>#include<stdlib.h>#include<stdbool.h>structNode{intdata;structNode*left;structNode*right;};structNode*newNode(intvalue){structNode*node=(structNode*)malloc(sizeof(structNode));node->data=value;node->left=NULL;node->right=NULL;returnnode;}boolhasNode(structNode*root,intvalue){if(root==NULL)returnfalse;returnroot->data==value||hasNode(root->left,value)||hasNode(root->right,value);}voidfindLca(structNode*root,intn1,intn2,structNode**ans,intdepth,int*bestDepth){if(root==NULL)return;// Check the current node as a potential LCA.if(hasNode(root,n1)&&hasNode(root,n2)){if(depth>*bestDepth){*bestDepth=depth;*ans=root;}}// Continue checking every node as a potential LCA.findLca(root->left,n1,n2,ans,depth+1,bestDepth);findLca(root->right,n1,n2,ans,depth+1,bestDepth);}structNode*lca(structNode*root,intn1,intn2){structNode*ans=NULL;intbestDepth=-1;findLca(root,n1,n2,&ans,0,&bestDepth);returnans;}intmain(){structNode*root=newNode(1);root->left=newNode(2);root->right=newNode(3);root->right->left=newNode(6);root->right->right=newNode(7);root->right->left->left=newNode(8);intn1=7;intn2=8;structNode*ans=lca(root,n1,n2);printf("%d\n",ans->data);return0;}
Java
classNode{intdata;Nodeleft,right;Node(intvalue){data=value;left=right=null;}}classGFG{staticbooleanhasNode(Noderoot,intvalue){if(root==null)returnfalse;returnroot.data==value||hasNode(root.left,value)||hasNode(root.right,value);}staticvoidfindLca(Noderoot,intn1,intn2,Node[]ans,intdepth,int[]bestDepth){if(root==null)return;// Check the current node as a potential LCA.if(hasNode(root,n1)&&hasNode(root,n2)){if(depth>bestDepth[0]){bestDepth[0]=depth;ans[0]=root;}}// Continue checking every node as a potential LCA.findLca(root.left,n1,n2,ans,depth+1,bestDepth);findLca(root.right,n1,n2,ans,depth+1,bestDepth);}staticNodelca(Noderoot,intn1,intn2){Node[]ans=newNode[1];int[]bestDepth={-1};findLca(root,n1,n2,ans,0,bestDepth);returnans[0];}publicstaticvoidmain(String[]args){Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.right.left=newNode(6);root.right.right=newNode(7);root.right.left.left=newNode(8);intn1=7;intn2=8;System.out.println(lca(root,n1,n2).data);}}
Python
classNode:def__init__(self,value):self.data=valueself.left=Noneself.right=NonedefhasNode(root,value):ifrootisNone:returnFalsereturn(root.data==valueorhasNode(root.left,value)orhasNode(root.right,value))deffindLca(root,n1,n2,ans,depth):ifrootisNone:returnans# Check the current node as a potential LCA.ifhasNode(root,n1)andhasNode(root,n2):ifdepth>ans[1]:ans=(root,depth)# Continue checking every node as a potential LCA.ans=findLca(root.left,n1,n2,ans,depth+1)ans=findLca(root.right,n1,n2,ans,depth+1)returnansdeflca(root,n1,n2):ans=findLca(root,n1,n2,(None,-1),0)returnans[0]if__name__=="__main__":root=Node(1)root.left=Node(2)root.right=Node(3)root.right.left=Node(6)root.right.right=Node(7)root.right.left.left=Node(8)n1=7n2=8print(lca(root,n1,n2).data)
C#
usingSystem;classNode{publicintdata;publicNodeleft,right;publicNode(intvalue){data=value;left=right=null;}}classGFG{staticboolhasNode(Noderoot,intvalue){if(root==null)returnfalse;returnroot.data==value||hasNode(root.left,value)||hasNode(root.right,value);}staticvoidfindLca(Noderoot,intn1,intn2,refNodeans,intdepth,refintbestDepth){if(root==null)return;// Check the current node as a potential LCA.if(hasNode(root,n1)&&hasNode(root,n2)){if(depth>bestDepth){bestDepth=depth;ans=root;}}// Continue checking every node as a potential LCA.findLca(root.left,n1,n2,refans,depth+1,refbestDepth);findLca(root.right,n1,n2,refans,depth+1,refbestDepth);}staticNodelca(Noderoot,intn1,intn2){Nodeans=null;intbestDepth=-1;findLca(root,n1,n2,refans,0,refbestDepth);returnans;}staticvoidMain(){Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.right.left=newNode(6);root.right.right=newNode(7);root.right.left.left=newNode(8);intn1=7;intn2=8;Console.WriteLine(lca(root,n1,n2).data);}}
JavaScript
classNode{constructor(value){this.data=value;this.left=null;this.right=null;}}functionhasNode(root,value){if(root===null)returnfalse;returnroot.data===value||hasNode(root.left,value)||hasNode(root.right,value);}functionfindLca(root,n1,n2,ans,depth){if(root===null)returnans;// Check the current node as a potential LCA.if(hasNode(root,n1)&&hasNode(root,n2)){if(depth>ans[1])ans=[root,depth];}// Continue checking every node as a potential LCA.ans=findLca(root.left,n1,n2,ans,depth+1);ans=findLca(root.right,n1,n2,ans,depth+1);returnans;}functionlca(root,n1,n2){constans=findLca(root,n1,n2,[null,-1],0);returnans[0];}// Driver Codeconstroot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.right.left=newNode(6);root.right.right=newNode(7);root.right.left.left=newNode(8);constn1=7;constn2=8;console.log(lca(root,n1,n2).data);
Output
3
[Better Approach] Storing Paths of Nodes from Root - O(n) Time and O(n) Space
The idea is to store the paths to the target nodes from the root in two separate arrays. Then start traversing from the 0th index and look simultaneously into the values stored in the arrays, the LCA is the last matching element in both the arrays.
Working of the Approach:
Find the path from the root to n1 and store it in an array.
Find the path from the root to n2 and store it in another array.
Start comparing both paths from the root.
Keep moving while the nodes at the same position are equal.
The last matching node is the Lowest Common Ancestor.
Return that node as the LCA.
Illustration:
Path from root to 7 = 1 -> 3-> 7 Path from root to 8 = 1 -> 3 -> 6 -> 8
We start checking from 0th index. As both of the values match, we move to the next index.
Now check for values at 1st index, they are also matching, so we move to the 2nd index.
Now, we check for 3rd index, there's a mismatch so we consider the previous value.
Therefore, the LCA of (7, 8) is 3.
C++
#include<bits/stdc++.h>usingnamespacestd;structNode{intdata;Node*left;Node*right;Node(intvalue){data=value;left=right=nullptr;}};boolfindPath(Node*root,intvalue,vector<Node*>&path){if(root==nullptr)returnfalse;path.push_back(root);if(root->data==value)returntrue;if(findPath(root->left,value,path)||findPath(root->right,value,path))returntrue;path.pop_back();returnfalse;}Node*lca(Node*root,intn1,intn2){vector<Node*>path1,path2;findPath(root,n1,path1);findPath(root,n2,path2);Node*ans=nullptr;// Compare both paths to find the last common node.inti=0;while(i<path1.size()&&i<path2.size()&&path1[i]==path2[i]){ans=path1[i];i++;}// Return the last common node as the LCA.returnans;}intmain(){Node*root=newNode(1);root->left=newNode(2);root->right=newNode(3);root->right->left=newNode(6);root->right->right=newNode(7);root->right->left->left=newNode(8);intn1=7;intn2=8;Node*ans=lca(root,n1,n2);cout<<ans->data<<endl;return0;}
C
#include<stdio.h>#include<stdlib.h>#include<stdbool.h>structNode{intdata;structNode*left;structNode*right;};structNode*newNode(intvalue){structNode*node=(structNode*)malloc(sizeof(structNode));node->data=value;node->left=node->right=NULL;returnnode;}boolfindPath(structNode*root,intvalue,structNode**path,int*pathLen){if(root==NULL)returnfalse;path[(*pathLen)++]=root;if(root->data==value)returntrue;if(findPath(root->left,value,path,pathLen)||findPath(root->right,value,path,pathLen))returntrue;(*pathLen)--;returnfalse;}structNode*lca(structNode*root,intn1,intn2){structNode*path1[100];structNode*path2[100];intlen1=0;intlen2=0;findPath(root,n1,path1,&len1);findPath(root,n2,path2,&len2);structNode*ans=NULL;// Compare both paths to find the last common node.inti=0;while(i<len1&&i<len2&&path1[i]==path2[i]){ans=path1[i];i++;}// Return the last common node as the LCA.returnans;}intmain(){structNode*root=newNode(1);root->left=newNode(2);root->right=newNode(3);root->right->left=newNode(6);root->right->right=newNode(7);root->right->left->left=newNode(8);intn1=7;intn2=8;structNode*ans=lca(root,n1,n2);printf("%d\n",ans->data);return0;}
Java
importjava.util.ArrayList;classNode{intdata;Nodeleft,right;Node(intvalue){data=value;left=right=null;}}classGFG{staticbooleanfindPath(Noderoot,intvalue,ArrayList<Node>path){if(root==null)returnfalse;path.add(root);if(root.data==value)returntrue;if(findPath(root.left,value,path)||findPath(root.right,value,path))returntrue;path.remove(path.size()-1);returnfalse;}staticNodelca(Noderoot,intn1,intn2){ArrayList<Node>path1=newArrayList<>();ArrayList<Node>path2=newArrayList<>();findPath(root,n1,path1);findPath(root,n2,path2);Nodeans=null;// Compare both paths to find the last common node.inti=0;while(i<path1.size()&&i<path2.size()&&path1.get(i)==path2.get(i)){ans=path1.get(i);i++;}// Return the last common node as the LCA.returnans;}publicstaticvoidmain(String[]args){Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.right.left=newNode(6);root.right.right=newNode(7);root.right.left.left=newNode(8);intn1=7;intn2=8;Nodeans=lca(root,n1,n2);System.out.println(ans.data);}}
Python
classNode:def__init__(self,value):self.data=valueself.left=Noneself.right=NonedeffindPath(root,value,path):ifrootisNone:returnFalsepath.append(root)ifroot.data==value:returnTrueif(findPath(root.left,value,path)orfindPath(root.right,value,path)):returnTruepath.pop()returnFalsedeflca(root,n1,n2):path1=[]path2=[]findPath(root,n1,path1)findPath(root,n2,path2)ans=None# Compare both paths to find the last common node.i=0while(i<len(path1)andi<len(path2)andpath1[i]ispath2[i]):ans=path1[i]i+=1# Return the last common node as the LCA.returnansif__name__=="__main__":root=Node(1)root.left=Node(2)root.right=Node(3)root.right.left=Node(6)root.right.right=Node(7)root.right.left.left=Node(8)n1=7n2=8ans=lca(root,n1,n2)print(ans.data)
C#
usingSystem;usingSystem.Collections.Generic;classNode{publicintdata;publicNodeleft,right;publicNode(intvalue){data=value;left=right=null;}}classGFG{staticboolfindPath(Noderoot,intvalue,List<Node>path){if(root==null)returnfalse;path.Add(root);if(root.data==value)returntrue;if(findPath(root.left,value,path)||findPath(root.right,value,path))returntrue;path.RemoveAt(path.Count-1);returnfalse;}staticNodelca(Noderoot,intn1,intn2){List<Node>path1=newList<Node>();List<Node>path2=newList<Node>();findPath(root,n1,path1);findPath(root,n2,path2);Nodeans=null;// Compare both paths to find the last common node.inti=0;while(i<path1.Count&&i<path2.Count&&path1[i]==path2[i]){ans=path1[i];i++;}// Return the last common node as the LCA.returnans;}staticvoidMain(){Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.right.left=newNode(6);root.right.right=newNode(7);root.right.left.left=newNode(8);intn1=7;intn2=8;Nodeans=lca(root,n1,n2);Console.WriteLine(ans.data);}}
JavaScript
classNode{constructor(value){this.data=value;this.left=null;this.right=null;}}functionfindPath(root,value,path){if(root===null)returnfalse;path.push(root);if(root.data===value)returntrue;if(findPath(root.left,value,path)||findPath(root.right,value,path))returntrue;path.pop();returnfalse;}functionlca(root,n1,n2){constpath1=[];constpath2=[];findPath(root,n1,path1);findPath(root,n2,path2);letans=null;// Compare both paths to find the last common node.leti=0;while(i<path1.length&&i<path2.length&&path1[i]===path2[i]){ans=path1[i];i++;}// Return the last common node as the LCA.returnans;}// Driver Codeconstroot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.right.left=newNode(6);root.right.right=newNode(7);root.right.left.left=newNode(8);constn1=7;constn2=8;constans=lca(root,n1,n2);console.log(ans.data);
Output
3
[Expected Approach] Single Traversal to Find LCA - O(n) Time and O(h) Space
The idea is to recursively search the tree for n1 and n2.
If the current node is NULL, return NULL.
If the current node matches either value, return it as a potential LCA. Then, recursively search the left and right subtrees. If both subtrees return non-null nodes, n1 and n2 are found in different subtrees, so the current node is their LCA.
Otherwise, return the non-null result from the subtree containing the required node.
Working of the Approach:
Start the traversal from the root.
If the current node is NULL, return NULL.
If the current node matches n1 or n2, return the current node.
Recursively find the LCA in the left subtree.
Recursively find the LCA in the right subtree.
If both results are non-null, n1 and n2 are found in different subtrees, so the current node is the LCA.
If only one result is non-null, return that result.
Return the final node as the LCA.
C++
#include<iostream>usingnamespacestd;classNode{public:intdata;Node*left,*right;Node(intvalue){data=value;left=right=nullptr;}};Node*lca(Node*root,intn1,intn2){if(root==nullptr)returnnullptr;// If either key matches with root data, return root.if(root->data==n1||root->data==n2)returnroot;Node*leftLca=lca(root->left,n1,n2);Node*rightLca=lca(root->right,n1,n2);// If both subtrees return a node, current root is the LCA.if(leftLca!=nullptr&&rightLca!=nullptr)returnroot;returnleftLca!=nullptr?leftLca:rightLca;}intmain(){Node*root=newNode(1);root->left=newNode(2);root->right=newNode(3);root->right->left=newNode(6);root->right->right=newNode(7);root->right->left->left=newNode(8);intn1=7;intn2=8;Node*ans=lca(root,n1,n2);cout<<ans->data<<endl;return0;}
C
#include<stdio.h>#include<stdlib.h>#include<stdbool.h>structNode{intdata;structNode*left;structNode*right;};structNode*newNode(intvalue){structNode*node=(structNode*)malloc(sizeof(structNode));node->data=value;node->left=NULL;node->right=NULL;returnnode;}structNode*lca(structNode*root,intn1,intn2){if(root==NULL)returnNULL;// If either key matches with root data, return root.if(root->data==n1||root->data==n2)returnroot;structNode*leftLca=lca(root->left,n1,n2);structNode*rightLca=lca(root->right,n1,n2);// If both subtrees return a node, current root is the LCA.if(leftLca!=NULL&&rightLca!=NULL)returnroot;returnleftLca!=NULL?leftLca:rightLca;}intmain(){structNode*root=newNode(1);root->left=newNode(2);root->right=newNode(3);root->right->left=newNode(6);root->right->right=newNode(7);root->right->left->left=newNode(8);intn1=7;intn2=8;structNode*ans=lca(root,n1,n2);printf("%d\n",ans->data);return0;}
Java
classNode{intdata;Nodeleft,right;Node(intvalue){data=value;left=right=null;}}classGFG{staticNodelca(Noderoot,intn1,intn2){if(root==null)returnnull;// If either key matches with root data, return root.if(root.data==n1||root.data==n2)returnroot;NodeleftLca=lca(root.left,n1,n2);NoderightLca=lca(root.right,n1,n2);// If both subtrees return a node, current root is the LCA.if(leftLca!=null&&rightLca!=null)returnroot;returnleftLca!=null?leftLca:rightLca;}publicstaticvoidmain(String[]args){Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.right.left=newNode(6);root.right.right=newNode(7);root.right.left.left=newNode(8);intn1=7;intn2=8;Nodeans=lca(root,n1,n2);System.out.println(ans.data);}}
Python
classNode:def__init__(self,value):self.data=valueself.left=Noneself.right=Nonedeflca(root,n1,n2):ifrootisNone:returnNone# If either key matches with root data, return root.ifroot.data==n1orroot.data==n2:returnrootleftLca=lca(root.left,n1,n2)rightLca=lca(root.right,n1,n2)# If both subtrees return a node, current root is the LCA.ifleftLcaisnotNoneandrightLcaisnotNone:returnrootreturnleftLcaifleftLcaisnotNoneelserightLcaif__name__=="__main__":root=Node(1)root.left=Node(2)root.right=Node(3)root.right.left=Node(6)root.right.right=Node(7)root.right.left.left=Node(8)n1=7n2=8ans=lca(root,n1,n2)print(ans.data)
C#
usingSystem;classNode{publicintdata;publicNodeleft,right;publicNode(intvalue){data=value;left=right=null;}}classGFG{staticNodelca(Noderoot,intn1,intn2){if(root==null)returnnull;// If either key matches with root data, return root.if(root.data==n1||root.data==n2)returnroot;NodeleftLca=lca(root.left,n1,n2);NoderightLca=lca(root.right,n1,n2);// If both subtrees return a node, current root is the LCA.if(leftLca!=null&&rightLca!=null)returnroot;returnleftLca!=null?leftLca:rightLca;}staticvoidMain(){Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.right.left=newNode(6);root.right.right=newNode(7);root.right.left.left=newNode(8);intn1=7;intn2=8;Nodeans=lca(root,n1,n2);Console.WriteLine(ans.data);}}
JavaScript
classNode{constructor(value){this.data=value;this.left=null;this.right=null;}}functionlca(root,n1,n2){if(root===null)returnnull;// If either key matches with root data, return root.if(root.data===n1||root.data===n2)returnroot;constleftLca=lca(root.left,n1,n2);constrightLca=lca(root.right,n1,n2);// If both subtrees return a node, current root is the LCA.if(leftLca!==null&&rightLca!==null)returnroot;returnleftLca!==null?leftLca:rightLca;}// Driver Codeconstroot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.right.left=newNode(6);root.right.right=newNode(7);root.right.left.left=newNode(8);constn1=7;constn2=8;constans=lca(root,n1,n2);console.log(ans.data);