Lowest Common Ancestor in a Binary Tree
Last Updated :
04 Oct, 2025
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:
Output: 2
Explanation: As shown below, LCA of 4 and 5 is 2.
Input:
Output: 3
Explanation: As shown below, LCA of 7 and 8 is 3.
[Naive Approach] Using Arrays to Store Paths of Nodes from Root - O(n) Time and O(n) Space
The idea is to store the paths of 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>
using namespace std;
// Node Structure
class Node {
public:
int data;
Node *left, *right;
Node(int x) {
data = x;
left = nullptr;
right = nullptr;
}
};
// Function to find path from root to given node.
bool findPath(Node* root, vector<Node*>& path, int n) {
if (root == nullptr)
return false;
// Store current node value in the path.
path.push_back(root);
if (root->data == n ||
findPath(root->left, path, n) ||
findPath(root->right, path, n))
return true;
// else remove root from path and return false
path.pop_back();
return false;
}
Node* lca(Node* root, int n1, int n2) {
vector<Node*> path1, path2;
// Find paths from root to n1
// and root to n2.
if (!findPath(root, path1, n1) ||
!findPath(root, path2, n2))
return nullptr;
// Compare the paths to get the first
// different value
int i;
for (i = 0; i < path1.size() && i < path2.size(); i++) {
if (path1[i] != path2[i])
return path1[i-1];
}
return path1[i-1];
}
int main() {
// construct the binary tree
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
// /
// 8
Node* root = new Node(1);
root->left = new Node(2);
root->right = new Node(3);
root->left->left = new Node(4);
root->left->right = new Node(5);
root->right->left = new Node(6);
root->right->right = new Node(7);
root->right->left->left = new Node(8);
Node* ans = lca(root, 7, 8);
cout<< ans->data;
return 0;
}
C
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// maximum number of nodes in path
#define MAX 1000
// Node Structure
struct Node {
int data;
struct Node* left;
struct Node* right;
};
// Function to create a new node
struct Node* createNode(int x) {
struct Node* node = (struct Node*)malloc(sizeof(struct Node));
node->data = x;
node->left = NULL;
node->right = NULL;
return node;
}
// Function to find path from root to given node
bool findPath(struct Node* root, struct Node* path[], int* pathLen, int n) {
if (root == NULL)
return false;
// Store current node in the path
path[(*pathLen)++] = root;
if (root->data == n)
return true;
if (findPath(root->left, path, pathLen, n) ||
findPath(root->right, path, pathLen, n))
return true;
// else remove root from path and return false
(*pathLen)--;
return false;
}
// Function to find LCA
struct Node* lca(struct Node* root, int n1, int n2) {
struct Node* path1[MAX], *path2[MAX];
int len1 = 0, len2 = 0;
// Find paths from root to n1 and root to n2
if (!findPath(root, path1, &len1, n1) ||
!findPath(root, path2, &len2, n2))
return NULL;
// Compare the paths to get the first different value
int i;
for (i = 0; i < len1 && i < len2; i++) {
if (path1[i] != path2[i])
return path1[i - 1];
}
return path1[i - 1];
}
int main() {
// Construct the binary tree
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
// /
// 8
struct Node* root = createNode(1);
root->left = createNode(2);
root->right = createNode(3);
root->left->left = createNode(4);
root->left->right = createNode(5);
root->right->left = createNode(6);
root->right->right = createNode(7);
root->right->left->left = createNode(8);
struct Node* ans = lca(root, 7, 8);
printf("%d\n", ans->data);
return 0;
}
Java
import java.util.ArrayList;
import java.util.List;
// Node Structure
class Node {
int data;
Node left, right;
Node(int value) {
data = value;
left = right = null;
}
}
class GfG {
static Node lca(Node root, int n1, int n2) {
List<Node> path1 = new ArrayList<>();
List<Node> path2 = new ArrayList<>();
// Find paths from root to n1
// and root to n2.
if(!findPath(root, path1, n1) ||
!findPath(root, path2, n2))
return null;
// Compare the paths to get the first
// different value
int i;
for(i = 0; i<path1.size() && i<path2.size(); i++) {
if(path1.get(i) != path2.get(i))
return path1.get(i-1);
}
return path1.get(i-1);
}
// Finds the path from root to given node
static boolean findPath(Node root, List<Node> path, int n) {
if (root == null) {
return false;
}
// Store current node
path.add(root);
if (root.data == n ||
findPath(root.left, path, n) ||
findPath(root.right, path, n)) {
return true;
}
// remove root from path and return false
path.remove(path.size() - 1);
return false;
}
public static void main(String[] args) {
// construct the binary tree
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
// /
// 8
Node root = new Node(1);
root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
root.right.left = new Node(6);
root.right.right = new Node(7);
root.right.left.left = new Node(8);
Node ans = lca(root, 7, 8);
System.out.println(ans.data);
}
}
Python
# Node Structure
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
# function to find path from root to node
def findPath(root, path, k):
if root is None:
return False
# Store current node in path
path.append(root)
if (root.data == k or
findPath(root.left, path, k)
or findPath(root.right, path, k)):
return True
# else remove root from path and return false
path.pop()
return False
def lca(root, n1, n2):
path1 = []
path2 = []
# Find paths from root to n1
# and root to n2.
if (not findPath(root, path1, n1) or not findPath(root, path2, n2)):
return None
# Compare the paths to get the first different value
i = 0
while(i < len(path1) and i < len(path2)):
if path1[i] != path2[i]:
break
i += 1
return path1[i-1]
if __name__ == '__main__':
# construct the binary tree
# 1
# / \
# 2 3
# / \ / \
# 4 5 6 7
# /
# 8
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
root.right.left = Node(6)
root.right.right = Node(7)
root.right.left.left = Node(8)
ans = lca(root, 7, 8)
print(ans.data)
C#
using System;
using System.Collections.Generic;
// Node Structure
class Node {
public int data;
public Node left, right;
public Node(int x) {
data = x;
left = null;
right = null;
}
}
class GfG {
// Function to find path from root to given node.
// returns true if node with value 'k' lies in the subtree of 'root'
static bool findPath(Node root, List<Node> path, int k) {
if (root == null)
return false;
// Store current node value in the path.
path.Add(root);
if (root.data == k ||
findPath(root.left, path, k) ||
findPath(root.right, path, k))
return true;
// else remove root from path and return false
path.RemoveAt(path.Count - 1);
return false;
}
static Node lca(Node root, int n1, int n2) {
List<Node> path1 = new List<Node>();
List<Node> path2 = new List<Node>();
// Find paths from root to n1
// and root to n2.
if (!findPath(root, path1, n1) ||
!findPath(root, path2, n2))
return null;
// Compare the paths to get the first
// different value
int i;
for (i = 0; i < path1.Count && i < path2.Count; i++) {
if (path1[i] != path2[i])
return path1[i - 1];
}
return path1[i - 1];
}
static void Main(string[] args) {
// construct the binary tree
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
// /
// 8
Node root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
root.right.left = new Node(6);
root.right.right = new Node(7);
root.right.left.left = new Node(8);
Node ans = lca(root, 7, 8);
Console.WriteLine(ans.data);
}
}
JavaScript
// Node Structure
class Node {
constructor(x) {
this.data = x;
this.left = null;
this.right = null;
}
}
// Function to find path from root to given node.
function findPath(root, path, k) {
if (root === null)
return false;
// Store current node value in the path.
path.push(root);
if (root.data === k ||
findPath(root.left, path, k) ||
findPath(root.right, path, k))
return true;
// else remove root from path and return false
path.pop();
return false;
}
function lca(root, n1, n2) {
let path1 = [];
let path2 = [];
// Find paths from root to n1
// and root to n2.
if (!findPath(root, path1, n1) ||
!findPath(root, path2, n2))
return null;
// Compare the paths to get the first
// different value
let i;
for (i = 0; i < path1.length && i < path2.length; i++) {
if (path1[i] !== path2[i])
return path1[i - 1];
}
return path1[i - 1];
}
// Driver code
// construct the binary tree
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
// /
// 8
let root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
root.right.left = new Node(6);
root.right.right = new Node(7);
root.right.left.left = new Node(8);
let ans = lca(root, 7, 8);
console.log(ans.data);
[Expected Approach] Using Single Traversal
The idea is to traverse the tree starting from the root. If any of the given keys (n1 and n2) matches with the root, then the root is LCA (assuming that both keys are present). If the root doesn't match with any of the keys, we go for the left and right subtree. The node which has one key present in its left subtree and the other key present in the right subtree is the LCA, else if, both keys lie in the left subtree, then the left subtree has LCA, else the LCA lies in the right subtree.
C++
#include <iostream>
using namespace std;
// Node Structure
class Node {
public:
Node *left, *right;
int data;
Node(int k) {
data = k;
left = nullptr;
right = nullptr;
}
};
Node* lca(Node* root, int n1, int n2) {
if (!root)
return nullptr;
// If either key matches with root data, return root
if (root->data == n1 || root->data == n2)
return root;
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 LCA
if (leftLca && rightLca)
return root;
// Otherwise check if left subtree or
// right subtree is LCA
return leftLca ? leftLca : rightLca;
}
int main() {
// construct the binary tree
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
// /
// 8
Node* root = new Node(1);
root->left = new Node(2);
root->right = new Node(3);
root->left->left = new Node(4);
root->left->right = new Node(5);
root->right->left = new Node(6);
root->right->right = new Node(7);
root->right->left->left = new Node(8);
Node* ans = lca(root, 7, 8);
cout<<ans->data;
return 0;
}
C
#include <stdio.h>
#include <stdlib.h>
// Node Structure
struct Node {
struct Node *left, *right;
int key;
};
struct Node* lca(struct Node* root, int n1, int n2) {
if (root == NULL)
return NULL;
// If either key matches with root data, return root
if (root->key == n1 || root->key == n2)
return root;
struct Node* leftLca = lca(root->left, n1, n2);
struct Node* 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 LCA
if (leftLca && rightLca)
return root;
// Otherwise check if left subtree or
// right subtree is LCA
return (leftLca != NULL) ? leftLca : rightLca;
}
struct Node* createnode(int key) {
struct Node* newnode =
(struct Node*)malloc(sizeof(struct Node));
newnode->key = key;
newnode->left = newnode->right = NULL;
return newnode;
}
int main() {
// construct the binary tree
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
// /
// 8
struct Node* root = createnode(1);
root->left = createnode(2);
root->right = createnode(3);
root->left->left = createnode(4);
root->left->right = createnode(5);
root->right->left = createnode(6);
root->right->right = createnode(7);
root->right->left->left = createnode(8);
struct Node* ans = lca(root, 7, 8);
printf("%d", ans->key);
return 0;
}
Java
// Node Structure
class Node {
Node left, right;
int data;
Node(int k) {
data = k;
left = null;
right = null;
}
}
class GFG {
static Node lca(Node root, int n1, int n2) {
if (root == null)
return null;
// If either key matches with root data, return root
if (root.data == n1 || root.data == n2)
return root;
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
// node is present in one subtree and the other is present
// in the other, so this node is the LCA
if (leftLca != null && rightLca != null)
return root;
// Otherwise check if left subtree or
// right subtree is LCA
return (leftLca != null) ? leftLca : rightLca;
}
public static void main(String[] args) {
// construct the binary tree
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
// /
// 8
Node root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
root.right.left = new Node(6);
root.right.right = new Node(7);
root.right.left.left = new Node(8);
Node ans = lca(root, 7, 8);
System.out.println(ans.data);
}
}
Python
# Node Structure
class Node:
def __init__(self, k):
self.data = k
self.left = None
self.right = None
def lca(root, n1, n2):
if not root:
return None
# If either key matches with root data, return root
if root.data == n1 or root.data == n2:
return root
leftLca = 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 LCA
if leftLca and rightLca:
return root
# Otherwise check if left subtree or
# right subtree is LCA
return leftLca if leftLca else rightLca
if __name__ == "__main__":
# construct the binary tree
# 1
# / \
# 2 3
# / \ / \
# 4 5 6 7
# /
# 8
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
root.right.left = Node(6)
root.right.right = Node(7)
root.right.left.left = Node(8)
ans = lca(root, 7, 8)
print(ans.data)
C#
using System;
// Node Structure
class Node {
public Node left, right;
public int data;
public Node(int k) {
data = k;
left = null;
right = null;
}
}
class GFG {
static Node lca(Node root, int n1, int n2) {
if (root == null)
return null;
// If either key matches with root data, return root
if (root.data == n1 || root.data == n2)
return root;
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 LCA
if (leftLca != null && rightLca != null)
return root;
// Otherwise check if left subtree or
// right subtree is LCA
return leftLca != null ? leftLca : rightLca;
}
static void Main() {
// Construct the binary tree
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
// /
// 8
Node root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
root.right.left = new Node(6);
root.right.right = new Node(7);
root.right.left.left = new Node(8);
Node ans = lca(root, 7, 8);
Console.WriteLine(ans.data);
}
}
JavaScript
// Node Structure
class Node {
constructor(k) {
this.left = null;
this.right = null;
this.data = k;
}
}
function lca(root, n1, n2) {
if (root === null)
return null;
// If either key matches with root data, return root
if (root.data === n1 || root.data === n2)
return root;
let leftLca = lca(root.left, n1, n2);
let 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 LCA
if (leftLca && rightLca)
return root;
// Otherwise check if left subtree or
// right subtree is LCA
return leftLca ? leftLca : rightLca;
}
// Construct the binary tree
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
// /
// 8
let root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
root.right.left = new Node(6);
root.right.right = new Node(7);
root.right.left.left = new Node(8);
let ans = lca(root, 7, 8);
console.log(ans.data);
Time Complexity: O(n)
Auxiliary Space: O(h), where h is the height of the tree.
Explore
DSA Fundamentals
Data Structures
Algorithms
Advanced
Interview Preparation
Practice Problem