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: n1 .data= 4, n2.data = 5
Output: 2 Explanation: As shown below, LCA of 4 and 5 is 2.
Input: n1.data = 7, n2.data = 8
Output: 3 Explanation: As shown below, LCA of 7 and 8 is 3.
[Naive Approach] Checking if each node is LCA - O(N^2) Time and O(h) space
The idea is to traverse the tree from root node, and for every node check if it is the LCA. A node is the LCA if its left subtree has one target node and right subtree has the other target node.
C++
#include<iostream>usingnamespacestd;// Node StructureclassNode{public:intdata;Node*left;Node*right;Node(intvalue){data=value;left=right=nullptr;}};// returns true if val is present // in the subtree of rootboolhasNode(Node*root,Node*node){if(root==nullptr)returnfalse;return(root==node)||hasNode(root->left,node)||hasNode(root->right,node);}Node*lca(Node*root,Node*n1,Node*n2){if(root==nullptr)returnnullptr;if(hasNode(root->left,n1)&&hasNode(root->right,n2))returnroot;if(hasNode(root->left,n2)&&hasNode(root->right,n1))returnroot;Node*lcaLeft=lca(root->left,n1,n2);Node*lcaRight=lca(root->right,n1,n2);returnlcaLeft!=nullptr?lcaLeft:lcaRight;}intmain(){// Create binary tree:// 1// / \ // 2 3// / \ // 6 7 // /// 8Node*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);// Node 7Node*n1=root->right->right;// Node 8Node*n2=root->right->left->left;Node*ans=lca(root,n1,n2);cout<<ans->data<<endl;}
C
#include<stdio.h>#include<stdlib.h>#include<stdbool.h>// Node StructurestructNode{intdata;structNode*left;structNode*right;};// Create a new nodestructNode*newNode(intvalue){structNode*node=(structNode*)malloc(sizeof(structNode));node->data=value;node->left=NULL;node->right=NULL;returnnode;}// returns true if val is present // in the subtree of rootboolhasNode(structNode*root,structNode*node){if(root==NULL)returnfalse;return(root==node)||hasNode(root->left,node)||hasNode(root->right,node);}structNode*lca(structNode*root,structNode*n1,structNode*n2){if(root==NULL)returnNULL;if(hasNode(root->left,n1)&&hasNode(root->right,n2))returnroot;if(hasNode(root->left,n2)&&hasNode(root->right,n1))returnroot;structNode*lcaLeft=lca(root->left,n1,n2);structNode*lcaRight=lca(root->right,n1,n2);return(lcaLeft!=NULL)?lcaLeft:lcaRight;}intmain(){// Create binary tree:// 1// / \ // 2 3// / \ // 6 7 // /// 8structNode*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);// Node 7structNode*n1=root->right->right;// Node 8structNode*n2=root->right->left->left;structNode*ans=lca(root,n1,n2);printf("%d\n",ans->data);}
Java
importjava.util.ArrayList;importjava.util.List;// Node StructureclassNode{intdata;Nodeleft,right;Node(intvalue){data=value;left=right=null;}}classGFG{// returns true if val is present// in the subtree of rootstaticbooleanhasNode(Noderoot,Nodenode){if(root==null)returnfalse;return(root==node)||hasNode(root.left,node)||hasNode(root.right,node);}staticNodelca(Noderoot,Noden1,Noden2){if(root==null)returnnull;if(hasNode(root.left,n1)&&hasNode(root.right,n2))returnroot;if(hasNode(root.left,n2)&&hasNode(root.right,n1))returnroot;NodelcaLeft=lca(root.left,n1,n2);NodelcaRight=lca(root.right,n1,n2);returnlcaLeft!=null?lcaLeft:lcaRight;}publicstaticvoidmain(String[]args){// Create binary tree:// 1// / \// 2 3// / \// 6 7 // /// 8Noderoot=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);// Node 7Noden1=root.right.right;// Node 8Noden2=root.right.left.left;Nodeans=lca(root,n1,n2);System.out.println(ans.data);}}
Python
# Node StructureclassNode:def__init__(self,value):self.data=valueself.left=Noneself.right=None# returns true if val is present # in the subtree of rootdefhasNode(root,node):ifrootisNone:returnFalsereturnroot==nodeor \
hasNode(root.left,node)or \
hasNode(root.right,node)deflca(root,n1,n2):ifrootisNone:returnNoneifhasNode(root.left,n1)andhasNode(root.right,n2):returnrootifhasNode(root.left,n2)andhasNode(root.right,n1):returnrootlcaLeft=lca(root.left,n1,n2)lcaRight=lca(root.right,n1,n2)returnlcaLeftiflcaLeftisnotNoneelselcaRight# Create binary tree:# 1# / \# 2 3# / \# 6 7 # /# 8root=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)# Node 7n1=root.right.right# Node 8n2=root.right.left.leftans=lca(root,n1,n2)print(ans.data)
C#
usingSystem;classNode{publicintdata;publicNodeleft,right;publicNode(intvalue){data=value;left=right=null;}}classGFG{// returns true if val is present // in the subtree of rootstaticboolhasNode(Noderoot,Nodenode){if(root==null)returnfalse;return(root==node)||hasNode(root.left,node)||hasNode(root.right,node);}staticNodelca(Noderoot,Noden1,Noden2){if(root==null)returnnull;if(hasNode(root.left,n1)&&hasNode(root.right,n2))returnroot;if(hasNode(root.left,n2)&&hasNode(root.right,n1))returnroot;NodelcaLeft=lca(root.left,n1,n2);NodelcaRight=lca(root.right,n1,n2);returnlcaLeft!=null?lcaLeft:lcaRight;}publicstaticvoidMain(){// Create binary tree:// 1// / \// 2 3// / \// 6 7 // /// 8Noderoot=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);// Node 7Noden1=root.right.right;// Node 8Noden2=root.right.left.left;Nodeans=lca(root,n1,n2);Console.WriteLine(ans.data);}}
Javascript
constDenque=require("denque");// Node StructureclassNode{constructor(value){this.data=value;this.left=null;this.right=null;}}// returns true if val is present in the subtree of rootfunctionhasNode(root,node){if(root===null)returnfalse;returnroot===node||hasNode(root.left,node)||hasNode(root.right,node);}functionlca(root,n1,n2){if(root===null)returnnull;if(hasNode(root.left,n1)&&hasNode(root.right,n2))returnroot;if(hasNode(root.left,n2)&&hasNode(root.right,n1))returnroot;constlcaLeft=lca(root.left,n1,n2);constlcaRight=lca(root.right,n1,n2);returnlcaLeft!==null?lcaLeft:lcaRight;}// Create binary tree:// 1// / \// 2 3// / \// 6 7 // /// 8constroot=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);// Node 7constn1=root.right.right;// Node 8constn2=root.right.left.left;constans=lca(root,n1,n2);console.log(ans.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.
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<iostream>#include<vector>usingnamespacestd;// Node StructureclassNode{public:intdata;Node*left;Node*right;Node(intvalue){data=value;left=right=nullptr;}};// Finds the path from root to given nodeboolfindPath(Node*root,vector<Node*>&path,Node*n){if(root==nullptr)returnfalse;// Store current nodepath.push_back(root);if(root==n||findPath(root->left,path,n)||findPath(root->right,path,n)){returntrue;}// remove root from path and return falsepath.pop_back();returnfalse;}Node*lca(Node*root,Node*n1,Node*n2){vector<Node*>path1,path2;// Find paths from root to n1 // and root to n2if(!findPath(root,path1,n1)||!findPath(root,path2,n2))returnnullptr;// Compare the paths to get // the first different valueinti=0;for(i=0;i<path1.size()&&i<path2.size();i++){if(path1[i]!=path2[i])returnpath1[i-1];}returnpath1[i-1];}intmain(){// Create binary tree:// 1// / \ // 2 3// / \ // 6 7// /// 8Node*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);Node*n1=root->right->right;Node*n2=root->right->left->left;Node*ans=lca(root,n1,n2);if(ans)cout<<ans->data<<endl;}
C
#include<stdio.h>#include<stdlib.h>#include<stdbool.h>// Node StructurestructNode{intdata;structNode*left;structNode*right;};// Create new nodestructNode*newNode(intvalue){structNode*node=(structNode*)malloc(sizeof(structNode));node->data=value;node->left=node->right=NULL;returnnode;}// Finds the path from root to given nodeboolfindPath(structNode*root,structNode**path,int*pathLen,structNode*n){if(root==NULL)returnfalse;// Store current nodepath[(*pathLen)++]=root;if(root==n||findPath(root->left,path,pathLen,n)||findPath(root->right,path,pathLen,n))returntrue;// remove root from path and return false(*pathLen)--;returnfalse;}structNode*lca(structNode*root,structNode*n1,structNode*n2){structNode*path1[100];intlen1=0;structNode*path2[100];intlen2=0;// Find paths from root to n1// and root to n2.if(!findPath(root,path1,&len1,n1)||!findPath(root,path2,&len2,n2))returnNULL;// Compare the paths to get the first// different valueinti=0;for(i=0;i<len1&&i<len2;i++){if(path1[i]!=path2[i])returnpath1[i-1];}returnpath1[i-1];}intmain(){// Create binary tree:// 1// / \ // 2 3// / \ // 6 7// /// 8structNode*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);structNode*n1=root->right->right;structNode*n2=root->right->left->left;structNode*ans=lca(root,n1,n2);if(ans!=NULL)printf("%d\n",ans->data);}
Java
importjava.util.ArrayList;importjava.util.List;// Node StructureclassNode{intdata;Nodeleft,right;Node(intvalue){data=value;left=right=null;}}classGFG{staticNodelca(Noderoot,Noden1,Noden2){List<Node>path1=newArrayList<>();List<Node>path2=newArrayList<>();// Find paths from root to n1// and root to n2.if(!findPath(root,path1,n1)||!findPath(root,path2,n2))returnnull;// Compare the paths to get the first// different valueinti=0;for(i=0;i<path1.size()&&i<path2.size();i++){if(path1.get(i)!=path2.get(i))returnpath1.get(i-1);}returnpath1.get(i-1);}// Finds the path from root to given nodestaticbooleanfindPath(Noderoot,List<Node>path,Noden){if(root==null){returnfalse;}// Store current nodepath.add(root);if(root==n||findPath(root.left,path,n)||findPath(root.right,path,n)){returntrue;}// remove root from path and return falsepath.remove(path.size()-1);returnfalse;}publicstaticvoidmain(String[]args){// Create binary tree:// 1// / \// 2 3// / \// 6 7// /// 8Noderoot=newNode(1);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);Noden1=root.right.right;Noden2=root.right.left.left;Nodeans=lca(root,n1,n2);System.out.println(ans.data);}}
Python
# Node StructureclassNode:def__init__(self,value):self.data=valueself.left=Noneself.right=None# Finds the path from root to given nodedeffindPath(root,path,n):ifrootisNone:returnFalse# Store current nodepath.append(root)ifroot==norfindPath(root.left,path,n)orfindPath(root.right,path,n):returnTrue# remove root from path and return falsepath.pop()returnFalsedeflca(root,n1,n2):path1=[]path2=[]# Find paths from root to n1 # and root to n2ifnotfindPath(root,path1,n1)ornotfindPath(root,path2,n2):returnNone# Compare the paths to get # the first different valuei=0whilei<len(path1)andi<len(path2):ifpath1[i]!=path2[i]:returnpath1[i-1]i+=1returnpath1[i-1]# Create binary tree:# 1# / \# 2 3# / \# 6 7# /# 8root=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=root.right.rightn2=root.right.left.leftans=lca(root,n1,n2)print(ans.data)
C#
usingSystem;usingSystem.Collections.Generic;// Node structureclassNode{publicintdata;publicNodeleft,right;publicNode(intvalue){data=value;left=right=null;}}classGFG{staticNodelca(Noderoot,Noden1,Noden2){List<Node>path1=newList<Node>();List<Node>path2=newList<Node>();// Find paths from root to n1 // and root to n2.if(!findPath(root,path1,n1)||!findPath(root,path2,n2))returnnull;// Compare the paths to // get the first different valueinti=0;for(i=0;i<path1.Count&&i<path2.Count;i++){if(path1[i]!=path2[i])returnpath1[i-1];}returnpath1[i-1];}// Finds the path from root to given nodestaticboolfindPath(Noderoot,List<Node>path,Noden){if(root==null)returnfalse;// Store current nodepath.Add(root);if(root==n||findPath(root.left,path,n)||findPath(root.right,path,n))returntrue;// remove root from path and return falsepath.RemoveAt(path.Count-1);returnfalse;}publicstaticvoidMain(){// Create binary tree:// 1// / \// 2 3// / \// 6 7// /// 8Noderoot=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);Noden1=root.right.right;Noden2=root.right.left.left;Nodeans=lca(root,n1,n2);Console.WriteLine(ans.data);}}
Javascript
constDenque=require("denque");// Node StructureclassNode{constructor(value){this.data=value;this.left=null;this.right=null;}}// Finds the path from root to given nodefunctionfindPath(root,path,n){if(root===null)returnfalse;// Store current nodepath.push(root);if(root===n||findPath(root.left,path,n)||findPath(root.right,path,n)){returntrue;}// remove root from path and return falsepath.pop();returnfalse;}functionlca(root,n1,n2){constpath1=[];constpath2=[];// Find paths from root to n1 // and root to n2if(!findPath(root,path1,n1)||!findPath(root,path2,n2))returnnull;// Compare the paths to // get the first different valueleti=0;for(i=0;i<path1.length&&i<path2.length;i++){if(path1[i]!==path2[i])returnpath1[i-1];}returnpath1[i-1];}// Create binary tree:// 1// / \// 2 3// / \// 6 7// /// 8constroot=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=root.right.right;constn2=root.right.left.left;constans=lca(root,n1,n2);console.log(ans.data);
Output
3
[Expected Approach] Using Single Traversal
In this approach, we start with the root node and recursively searches for the given nodes n1 and n2. If the current root is null, it returns null. If the root matches either of the keys, it returns the root as a potential LCA. Then, it recursively checks the left and right subtrees. If both the left and right recursive calls return non-null values, it means one key is in the left subtree and the other is in the right subtree, so the current root is the LCA. If only one subtree contains the keys, the recursive call returns the non-null subtree result as the LCA.
C++
#include<iostream>usingnamespacestd;// Node StructureclassNode{public:Node*left,*right;intdata;Node(intk){data=k;left=nullptr;right=nullptr;}};Node*lca(Node*root,Node*n1,Node*n2){if(!root)returnnullptr;// If either key matches with root data, return rootif(root==n1||root==n2)returnroot;Node*leftLca=lca(root->left,n1,n2);Node*rightLca=lca(root->right,n1,n2);// If both of the above calls return Non-NULL, then one// data is present in one subtree and the other is present// in the other, so this node is the LCAif(leftLca&&rightLca)returnroot;// Otherwise check if left subtree or // right subtree is LCAreturnleftLca?leftLca:rightLca;}intmain(){// Create binary tree:// 1// / \ // 2 3// / \ // 6 7 // /// 8Node*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);Node*n1=root->right->right;Node*n2=root->right->left->left;Node*ans=lca(root,n1,n2);cout<<ans->data;return0;}
C
#include<stdio.h>#include<stdlib.h>// Node StructurestructNode{structNode*left,*right;intkey;};structNode*lca(structNode*root,structNode*n1,structNode*n2){if(root==NULL)returnNULL;// If either key matches with root data, return rootif(root==n1||root==n2)returnroot;structNode*leftLca=lca(root->left,n1,n2);structNode*rightLca=lca(root->right,n1,n2);// If both of the above calls return Non-NULL, then one// key is present in once subtree and other is present// in other, so this node is the LCAif(leftLca&&rightLca)returnroot;// Otherwise check if left subtree or // right subtree is LCAreturn(leftLca!=NULL)?leftLca:rightLca;}structNode*createnode(intkey){structNode*newnode=(structNode*)malloc(sizeof(structNode));newnode->key=key;newnode->left=newnode->right=NULL;returnnewnode;}intmain(){// construct the binary tree// 1// / \ // 2 3// / \ / \ // 4 5 6 7 // /// 8structNode*root=createnode(1);root->left=createnode(2);root->right=createnode(3);root->right->left=createnode(6);root->right->right=createnode(7);root->right->left->left=createnode(8);structNode*n1=root->right->right;structNode*n2=root->right->left->left;structNode*ans=lca(root,n1,n2);printf("%d",ans->key);return0;}
Java
// Node StructureclassNode{Nodeleft,right;intdata;Node(intk){data=k;left=null;right=null;}}classGFG{staticNodelca(Noderoot,Noden1,Noden2){if(root==null)returnnull;// If either key matches with root data, return rootif(root==n1||root==n2)returnroot;NodeleftLca=lca(root.left,n1,n2);NoderightLca=lca(root.right,n1,n2);// If both of the above calls return Non-NULL, then one// node is present in one subtree and the other is present// in the other, so this node is the LCAif(leftLca!=null&&rightLca!=null)returnroot;// Otherwise check if left subtree or // right subtree is LCAreturn(leftLca!=null)?leftLca:rightLca;}publicstaticvoidmain(String[]args){// Create binary tree:// 1// / \// 2 3// / \// 6 7 // /// 8Noderoot=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);Noden1=root.right.right;Noden2=root.right.left.left;Nodeans=lca(root,n1,n2);System.out.println(ans.data);}}
Python
# Node StructureclassNode:def__init__(self,k):self.data=kself.left=Noneself.right=Nonedeflca(root,n1,n2):ifnotroot:returnNone# If either key matches with root data, return rootifroot==n1orroot==n2:returnrootleftLca=lca(root.left,n1,n2)rightLca=lca(root.right,n1,n2)# If both of the above calls return Non-NULL, then one# data is present in one subtree and the other is present# in the other, so this node is the LCAifleftLcaandrightLca:returnroot# Otherwise check if left subtree or # right subtree is LCAreturnleftLcaifleftLcaelserightLcaif__name__=="__main__":# Create binary tree:# 1# / \# 2 3# / \# 6 7 # /# 8root=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=root.right.right;n2=root.right.left.left;ans=lca(root,n1,n2);print(ans.data)
C#
usingSystem;// Node StructureclassNode{publicNodeleft,right;publicintdata;publicNode(intk){data=k;left=null;right=null;}}classGFG{staticNodelca(Noderoot,Noden1,Noden2){if(root==null)returnnull;// If either key matches with root data, return rootif(root==n1||root==n2)returnroot;NodeleftLca=lca(root.left,n1,n2);NoderightLca=lca(root.right,n1,n2);// If both of the above calls return Non-NULL, then one// data is present in one subtree and the other is present// in the other, so this node is the LCAif(leftLca!=null&&rightLca!=null)returnroot;// Otherwise check if left subtree or // right subtree is LCAreturnleftLca!=null?leftLca:rightLca;}staticvoidMain(){// Create binary tree:// 1// / \// 2 3// / \// 6 7 // /// 8Noderoot=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);Noden1=root.right.right;Noden2=root.right.left.left;Nodeans=lca(root,n1,n2);Console.WriteLine(ans.data);}}
JavaScript
// Node StructureclassNode{constructor(k){this.left=null;this.right=null;this.data=k;}}functionlca(root,n1,n2){if(root===null)returnnull;// If either key matches with root data, return rootif(root===n1||root===n2)returnroot;letleftLca=lca(root.left,n1,n2);letrightLca=lca(root.right,n1,n2);// If both of the above calls return Non-NULL, then one// data is present in one subtree and the other is present// in the other, so this node is the LCAif(leftLca&&rightLca)returnroot;// Otherwise check if left subtree or // right subtree is LCAreturnleftLca?leftLca:rightLca;}// Create binary tree:// 1// / \// 2 3// / \// 6 7 // /// 8letroot=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);letn1=root.right.right;letn2=root.right.left.left;letans=lca(root,n1,n2);console.log(ans.data);
Output
3
Time Complexity: O(n) Auxiliary Space: O(h), where h is the height of the tree.