Given the root of a Binary Search Tree and two node 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 are always present in the Binary Search Tree.
Examples:
Input: n1.data = 4, n2.data = 14
Output: 8 Explanation: 8 is the lowest common ancestor (LCA) of nodes 4 and 14, as it is the deepest node that is an ancestor of both.
Input: n1.data = 10, n2.data = 14
Output: 12 Explanation: 12 is the lowest common ancestor (LCA) of nodes 10 and 14, as it is the deepest node that is an ancestor of both.
[Naive Approach] LCA by Normal Binary Tree Methods - O(n) Time and O(n) Space
We can use any of the approaches discussed in Lowest Common Ancestorin a Binary Tree, which run in O(n) time, where n is the number of nodes in the BST. However, we can achieve a better time complexity by leveraging the properties of the BST.
[Better Approach] Using BST Properties (Recursive Approach) - O(h) Time and O(h) Space
This approach is based on the observation that the LCA is the lowest (closest to root) node whose value lies between n1 and n2.
In a Binary search tree, while traversing the tree from top to bottom the first node which lies in between the two numbers n1 and n2 is the LCA of the nodes, i.e. the first node n with the lowest depth which lies in between n1 and n2 (n1 <= n <= n2, assuming n1 < n2).
So, we just recursively traverse the BST , if node's value is greater than both n1 and n2 then our LCA lies in the left side of the node, if it is smaller than both n1 and n2, then LCA lies on the right side. Otherwise, the root is LCA (assuming that both n1 and n2 are present in BST).
C++
//Driver Code Starts#include<iostream>usingnamespacestd;// Node structureclassNode{public:intdata;Node*left;Node*right;Node(intval){data=val;left=right=nullptr;}};//Driver Code EndsNode*LCA(Node*root,Node*n1,Node*n2){if(root==nullptr)returnnullptr;// If both n1 and n2 are smaller than // root, go to left subtreeif(root->data>n1->data&&root->data>n2->data)returnLCA(root->left,n1,n2);// If both n1 and n2 are greater than // root, go to right subtreeif(root->data<n1->data&&root->data<n2->data)returnLCA(root->right,n1,n2);// If nodes n1 and n2 are on the opposite sides, // then root is the LCAreturnroot;}//Driver Code Startsintmain(){// Representation of input BST:// 20// / \ // 8 22// / \ // 4 12 // / \ // 10 14 Node*root=newNode(20);root->left=newNode(8);root->right=newNode(22);root->left->left=newNode(4);root->left->right=newNode(12);root->left->right->left=newNode(10);root->left->right->right=newNode(14);// Node 4Node*n1=root->left->left;// Node 14Node*n2=root->left->right->right;Node*res=LCA(root,n1,n2);cout<<res->data<<endl;return0;}//Driver Code Ends
C
//Driver Code Starts#include<stdio.h>#include<stdlib.h>// Node structuretypedefstructNode{intdata;structNode*left;structNode*right;}Node;Node*newNode(intval){Node*node=(Node*)malloc(sizeof(Node));node->data=val;node->left=node->right=NULL;returnnode;}//Driver Code EndsNode*LCA(Node*root,Node*n1,Node*n2){if(root==NULL)returnNULL;// If both n1 and n2 are smaller than root, // go to left subtreeif(root->data>n1->data&&root->data>n2->data)returnLCA(root->left,n1,n2);// If both n1 and n2 are greater than root, // go to right subtreeif(root->data<n1->data&&root->data<n2->data)returnLCA(root->right,n1,n2);// If nodes n1 and n2 are on the opposite sides, // root is the LCAreturnroot;}//Driver Code Startsintmain(){// Representation of input BST:// 20// / \ // 8 22// / \ // 4 12 // / \ // 10 14 Node*root=newNode(20);root->left=newNode(8);root->right=newNode(22);root->left->left=newNode(4);root->left->right=newNode(12);root->left->right->left=newNode(10);root->left->right->right=newNode(14);// Node 4Node*n1=root->left->left;// Node 14Node*n2=root->left->right->right;Node*res=LCA(root,n1,n2);printf("%d",res->data);return0;}//Driver Code Ends
Java
//Driver Code Starts// Node structureclassNode{intdata;Nodeleft,right;Node(intval){data=val;left=right=null;}}classGFG{//Driver Code EndsstaticNodeLCA(Noderoot,Noden1,Noden2){if(root==null)returnnull;// If both n1 and n2 are smaller than root, // go to left subtreeif(root.data>n1.data&&root.data>n2.data)returnLCA(root.left,n1,n2);// If both n1 and n2 are greater than root, // go to right subtreeif(root.data<n1.data&&root.data<n2.data)returnLCA(root.right,n1,n2);// If nodes n1 and n2 are on the opposite sides, // root is the LCAreturnroot;}//Driver Code Startspublicstaticvoidmain(String[]args){// Representation of input BST:// 20// / \// 8 22// / \ // 4 12 // / \ // 10 14 Noderoot=newNode(20);root.left=newNode(8);root.right=newNode(22);root.left.left=newNode(4);root.left.right=newNode(12);root.left.right.left=newNode(10);root.left.right.right=newNode(14);// Node 4Noden1=root.left.left;// Node 14Noden2=root.left.right.right;Noderes=LCA(root,n1,n2);System.out.println(res.data);}}//Driver Code Ends
Python
#Driver Code Starts# Node structureclassNode:def__init__(self,val):self.data=valself.left=Noneself.right=None#Driver Code EndsdefLCA(root,n1,n2):ifrootisNone:returnNone# If both n1 and n2 are smaller than root, # go to left subtreeifroot.data>n1.dataandroot.data>n2.data:returnLCA(root.left,n1,n2)# If both n1 and n2 are greater than root, # go to right subtreeifroot.data<n1.dataandroot.data<n2.data:returnLCA(root.right,n1,n2)# If nodes n1 and n2 are on the opposite sides, # root is the LCAreturnroot#Driver Code Startsif__name__=="__main__":# Representation of input BST:# 20# / \# 8 22# / \ # 4 12 # / \ # 10 14 root=Node(20)root.left=Node(8)root.right=Node(22)root.left.left=Node(4)root.left.right=Node(12)root.left.right.left=Node(10)root.left.right.right=Node(14)# Node 4n1=root.left.left# Node 14n2=root.left.right.rightres=LCA(root,n1,n2)print(res.data)#Driver Code Ends
C#
//Driver Code StartsusingSystem;// Node structureclassNode{publicintdata;publicNodeleft,right;publicNode(intval){data=val;left=right=null;}}classGFG{//Driver Code EndsstaticNodeLCA(Noderoot,Noden1,Noden2){if(root==null)returnnull;// If both n1 and n2 are smaller than root,// go to left subtreeif(root.data>n1.data&&root.data>n2.data)returnLCA(root.left,n1,n2);// If both n1 and n2 are greater than root, // go to right subtreeif(root.data<n1.data&&root.data<n2.data)returnLCA(root.right,n1,n2);// If nodes n1 and n2 are on the opposite sides, // root is the LCAreturnroot;}//Driver Code StartsstaticvoidMain(string[]args){// Representation of input BST:// 20// / \// 8 22// / \ // 4 12 // / \ // 10 14 Noderoot=newNode(20);root.left=newNode(8);root.right=newNode(22);root.left.left=newNode(4);root.left.right=newNode(12);root.left.right.left=newNode(10);root.left.right.right=newNode(14);// Node 4Noden1=root.left.left;// Node 14Noden2=root.left.right.right;Noderes=LCA(root,n1,n2);Console.WriteLine(res.data);}}//Driver Code Ends
JavaScript
//Driver Code Starts// Node structureclassNode{constructor(val){this.data=val;this.left=null;this.right=null;}}//Driver Code EndsfunctionLCA(root,n1,n2){if(root===null)returnnull;// If both n1 and n2 are smaller than root, go to left subtreeif(root.data>n1.data&&root.data>n2.data)returnLCA(root.left,n1,n2);// If both n1 and n2 are greater than root, go to right subtreeif(root.data<n1.data&&root.data<n2.data)returnLCA(root.right,n1,n2);// If nodes n1 and n2 are on the opposite sides, root is the LCAreturnroot;}//Driver Code Starts// Driver Code// Representation of input BST:// 20// / \// 8 22// / \ // 4 12 // / \ // 10 14 constroot=newNode(20);root.left=newNode(8);root.right=newNode(22);root.left.left=newNode(4);root.left.right=newNode(12);root.left.right.left=newNode(10);root.left.right.right=newNode(14);// Node 4constn1=root.left.left;// Node 14constn2=root.left.right.right;constres=LCA(root,n1,n2);console.log(res.data);//Driver Code Ends
Output
8
[Expected Approach] Using BST Properties (Iterative Method) - O(h) Time and O(1) Space
The auxiliary space in the above method can be optimized by eliminating recursion. Below is the iterative implementation of this approach.
C++
//Driver Code Starts#include<iostream>usingnamespacestd;// Node structureclassNode{public:intdata;Node*left;Node*right;Node(intval){data=val;left=right=nullptr;}};//Driver Code EndsNode*LCA(Node*root,Node*n1,Node*n2){while(root!=nullptr){// If both n1 and n2 are smaller than root,// then LCA lies in leftif(root->data>n1->data&&root->data>n2->data)root=root->left;// If both n1 and n2 are greater than root,// then LCA lies in rightelseif(root->data<n1->data&&root->data<n2->data)root=root->right;// Else Ancestor is foundelsebreak;}returnroot;}//Driver Code Startsintmain(){// Representation of input BST:// 20// / \ // 8 22// / \ // 4 12 // / \ // 10 14 Node*root=newNode(20);root->left=newNode(8);root->right=newNode(22);root->left->left=newNode(4);root->left->right=newNode(12);root->left->right->left=newNode(10);root->left->right->right=newNode(14);// Node 4Node*n1=root->left->left;// Node 14Node*n2=root->left->right->right;Node*res=LCA(root,n1,n2);cout<<res->data<<endl;return0;}//Driver Code Ends
C
//Driver Code Starts#include<stdio.h>#include<stdlib.h>// Node structuretypedefstructNode{intdata;structNode*left;structNode*right;}Node;Node*createNode(intval){Node*newNode=(Node*)malloc(sizeof(Node));newNode->data=val;newNode->left=newNode->right=NULL;returnnewNode;}//Driver Code EndsNode*LCA(Node*root,Node*n1,Node*n2){while(root!=NULL){// If both n1 and n2 are smaller than root,// then LCA lies in leftif(root->data>n1->data&&root->data>n2->data)root=root->left;// If both n1 and n2 are greater than root,// then LCA lies in rightelseif(root->data<n1->data&&root->data<n2->data)root=root->right;// Else Ancestor is foundelsebreak;}returnroot;}//Driver Code Startsintmain(){// Representation of input BST:// 20// / \ // 8 22// / \ // 4 12 // / \ // 10 14 Node*root=createNode(20);root->left=createNode(8);root->right=createNode(22);root->left->left=createNode(4);root->left->right=createNode(12);root->left->right->left=createNode(10);root->left->right->right=createNode(14);// Node 4Node*n1=root->left->left;// Node 14Node*n2=root->left->right->right;Node*res=LCA(root,n1,n2);printf("%d",res->data);return0;}//Driver Code Ends
Java
//Driver Code Starts// Node structureclassNode{intdata;Nodeleft,right;Node(intval){data=val;left=right=null;}}classGFG{//Driver Code EndsstaticNodeLCA(Noderoot,Noden1,Noden2){while(root!=null){// If both n1 and n2 are smaller than root,// then LCA lies in leftif(root.data>n1.data&&root.data>n2.data)root=root.left;// If both n1 and n2 are greater than root,// then LCA lies in rightelseif(root.data<n1.data&&root.data<n2.data)root=root.right;// Else Ancestor is foundelsebreak;}returnroot;}//Driver Code Startspublicstaticvoidmain(String[]args){// Representation of input BST:// 20// / \// 8 22// / \// 4 12// / \// 10 14Noderoot=newNode(20);root.left=newNode(8);root.right=newNode(22);root.left.left=newNode(4);root.left.right=newNode(12);root.left.right.left=newNode(10);root.left.right.right=newNode(14);// Node 4Noden1=root.left.left;// Node 14Noden2=root.left.right.right;Noderes=LCA(root,n1,n2);System.out.println(res.data);}}//Driver Code Ends
Python
#Driver Code Starts# Node structureclassNode:def__init__(self,data):self.data=dataself.left=Noneself.right=None#Driver Code EndsdefLCA(root,n1,n2):whileroot:# If both n1 and n2 are smaller than root,# then LCA lies in leftifroot.data>n1.dataandroot.data>n2.data:root=root.left# If both n1 and n2 are greater than root,# then LCA lies in rightelifroot.data<n1.dataandroot.data<n2.data:root=root.right# Else Ancestor is foundelse:breakreturnroot#Driver Code Startsif__name__=="__main__":# Representation of input BST:# 20# / \# 8 22# / \ # 4 12 # / \ # 10 14 root=Node(20)root.left=Node(8)root.right=Node(22)root.left.left=Node(4)root.left.right=Node(12)root.left.right.left=Node(10)root.left.right.right=Node(14)# Node 4n1=root.left.left# Node 14n2=root.left.right.rightres=LCA(root,n1,n2)print(res.data)#Driver Code Ends
C#
//Driver Code StartsusingSystem;// Node structureclassNode{publicintdata;publicNodeleft,right;publicNode(intval){data=val;left=right=null;}}classGFG{//Driver Code EndsstaticNodeLCA(Noderoot,Noden1,Noden2){while(root!=null){// If both n1 and n2 are smaller than root,// then LCA lies in leftif(root.data>n1.data&&root.data>n2.data)root=root.left;// If both n1 and n2 are greater than root,// then LCA lies in rightelseif(root.data<n1.data&&root.data<n2.data)root=root.right;// Else Ancestor is foundelsebreak;}returnroot;}//Driver Code StartsstaticvoidMain(string[]args){// Representation of input BST:// 20// / \// 8 22// / \ // 4 12 // / \ // 10 14 Noderoot=newNode(20);root.left=newNode(8);root.right=newNode(22);root.left.left=newNode(4);root.left.right=newNode(12);root.left.right.left=newNode(10);root.left.right.right=newNode(14);// Node 4Noden1=root.left.left;// Node 14Noden2=root.left.right.right;Noderes=LCA(root,n1,n2);Console.WriteLine(res.data);}}//Driver Code Ends
JavaScript
//Driver Code Starts// Node structureclassNode{constructor(data){this.data=data;this.left=null;this.right=null;}}//Driver Code EndsfunctionLCA(root,n1,n2){while(root!==null){// If both n1 and n2 are smaller than root,// then LCA lies in leftif(root.data>n1.data&&root.data>n2.data)root=root.left;// If both n1 and n2 are greater than root,// then LCA lies in rightelseif(root.data<n1.data&&root.data<n2.data)root=root.right;// Else Ancestor is foundelsebreak;}returnroot;}//Driver Code Starts// Representation of input BST:// 20// / \// 8 22// / \ // 4 12 // / \ // 10 14 constroot=newNode(20);root.left=newNode(8);root.right=newNode(22);root.left.left=newNode(4);root.left.right=newNode(12);root.left.right.left=newNode(10);root.left.right.right=newNode(14);// Node 4constn1=root.left.left;// Node 14constn2=root.left.right.right;constres=LCA(root,n1,n2);console.log(res.data);//Driver Code Ends