Given the root of a Binary Search Tree (BST) with unique node values and two nodes n1 and n2 (n1 != n2), find their Lowest Common Ancestor (LCA).
The Lowest Common Ancestor (LCA) of two nodes is defined as the deepest node in the tree that has both n1 and n2 as descendants, where a node can be a descendant of itself.
Examples:
Input: root = [20, 8, 22, 4, 12, N, N, N, N, 10 , 14 ], 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: root = [20, 8, 22, 4, 12, N, N, N, N, 10 , 14 ], 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 takes advantage of the Binary Search Tree (BST) property to avoid searching the entire tree. Starting from the root, if both n1 and n2 have values smaller than the current node, then the LCA must be present in the left subtree. Similarly, if both values are greater than the current node, then the LCA must be present in the right subtree. Otherwise, the current node is the first node where the paths to n1 and n2 split, making it their Lowest Common Ancestor.
Consider: root = [20, 8, 22, 4, 12, N, N, N, N, 10 , 14 ], n1-> data = 10, n2-> data = 14
Start from the root (20).
Both 10 and 14 are smaller than 20.
So, the LCA cannot be in the right subtree.
Move to the left child (8).
At node 8.
Both 10 and 14 are greater than 8.
So, the LCA cannot be in the left subtree.
Move to the right child (12).
At node 12.
10 is smaller than 12, while 14 is greater than 12.
This means one node is in the left subtree and the other is in the right subtree.
Therefore, 12 is the first node where their paths split, so it is the Lowest Common Ancestor (LCA).
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*findLCA(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)returnfindLCA(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)returnfindLCA(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=findLCA(root,n1,n2);cout<<res->data<<endl;return0;}//Driver Code Ends
Java
//Driver Code Starts// Node structureclassNode{intdata;Nodeleft,right;Node(intval){data=val;left=right=null;}}classGFG{//Driver Code EndspublicstaticNodefindLCA(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)returnfindLCA(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)returnfindLCA(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=findLCA(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 EndsdeffindLCA(root,n1,n2):ifrootisNone:returnNone# If both n1 and n2 are smaller than root, # go to left subtreeifroot.data>n1.dataandroot.data>n2.data:returnfindLCA(root.left,n1,n2)# If both n1 and n2 are greater than root, # go to right subtreeifroot.data<n1.dataandroot.data<n2.data:returnfindLCA(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=findLCA(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 EndspublicstaticNodefindLCA(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)returnfindLCA(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)returnfindLCA(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=findLCA(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 EndsfunctionfindLCA(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)returnfindLCA(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)returnfindLCA(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=findLCA(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 recursive approach can be optimized by eliminating the recursion stack. Instead of making recursive calls, we iteratively traverse the BST from the root. At each node, if both n1 and n2 are smaller than the current node, we move to the left child. If both are greater, we move to the right child. Otherwise, the current node is the first node where the paths to n1 and n2 diverge, making it their Lowest Common Ancestor.
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*findLCA(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=findLCA(root,n1,n2);cout<<res->data<<endl;return0;}//Driver Code Ends
Java
//Driver Code Starts// Node structureclassNode{intdata;Nodeleft,right;Node(intval){data=val;left=right=null;}}classGFG{//Driver Code EndsstaticNodefindLCA(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=findLCA(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 EndsdeffindLCA(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=findLCA(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 EndsstaticNodefindLCA(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=findLCA(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 EndsfunctionfindLCA(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=findLCA(root,n1,n2);console.log(res.data);//Driver Code Ends