Lowest Common Ancestor in a Binary Tree

Last Updated : 20 Sep, 2026

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

10

Output: 3
Explanation: LCA of 7 and 8 is 3.

111

Input: root = [1, 2, 3, 4, 5, 6, 7], n1 = 4, n2 = 5

420046698

Output: 2
Explanation: LCA of 4 and 5 is 2.

420046699
Try It Yourself
redirect icon

[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>
using namespace std;

class Node {
public:
    int data;
    Node* left;
    Node* right;

    Node(int value) {
        data = value;
        left = right = nullptr;
    }
};

bool hasNode(Node* root, int value) {
    if (root == nullptr)
        return false;

    return root->data == value ||
           hasNode(root->left, value) ||
           hasNode(root->right, value);
}

void findLca(Node* root, int n1, int n2,
             Node*& ans, int depth, 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, int n1, int n2) {
    Node* ans = nullptr;
    int bestDepth = -1;

    findLca(root, n1, n2, ans, 0, bestDepth);

    return ans;
}

int main() {
    Node* root = new Node(1);
    root->left = new Node(2);
    root->right = new Node(3);
    root->right->left = new Node(6);
    root->right->right = new Node(7);
    root->right->left->left = new Node(8);

    int n1 = 7;
    int n2 = 8;

    cout << lca(root, n1, n2)->data << endl;

    return 0;
}
C
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

struct Node {
    int data;
    struct Node* left;
    struct Node* right;
};

struct Node* newNode(int value) {
    struct Node* node = (struct Node*)malloc(sizeof(struct Node));
    node->data = value;
    node->left = NULL;
    node->right = NULL;
    return node;
}

bool hasNode(struct Node* root, int value) {
    if (root == NULL)
        return false;

    return root->data == value ||
           hasNode(root->left, value) ||
           hasNode(root->right, value);
}

void findLca(struct Node* root, int n1, int n2,
             struct Node** ans, int depth, 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);
}

struct Node* lca(struct Node* root, int n1, int n2) {
    struct Node* ans = NULL;
    int bestDepth = -1;

    findLca(root, n1, n2, &ans, 0, &bestDepth);

    return ans;
}

int main() {
    struct 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);

    int n1 = 7;
    int n2 = 8;

    struct Node* ans = lca(root, n1, n2);

    printf("%d\n", ans->data);

    return 0;
}
Java
class Node {
    int data;
    Node left, right;

    Node(int value) {
        data = value;
        left = right = null;
    }
}

class GFG {

    static boolean hasNode(Node root, int value) {
        if (root == null)
            return false;

        return root.data == value ||
               hasNode(root.left, value) ||
               hasNode(root.right, value);
    }

    static void findLca(Node root, int n1, int n2,
                        Node[] ans, int depth, 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);
    }

    static Node lca(Node root, int n1, int n2) {
        Node[] ans = new Node[1];
        int[] bestDepth = {-1};

        findLca(root, n1, n2, ans, 0, bestDepth);

        return ans[0];
    }

    public static void main(String[] args) {
        Node root = new Node(1);
        root.left = new Node(2);
        root.right = new Node(3);
        root.right.left = new Node(6);
        root.right.right = new Node(7);
        root.right.left.left = new Node(8);

        int n1 = 7;
        int n2 = 8;

        System.out.println(lca(root, n1, n2).data);
    }
}
Python
class Node:
    def __init__(self, value):
        self.data = value
        self.left = None
        self.right = None


def hasNode(root, value):
    if root is None:
        return False

    return (root.data == value or
            hasNode(root.left, value) or
            hasNode(root.right, value))


def findLca(root, n1, n2, ans, depth):
    if root is None:
        return ans

    # Check the current node as a potential LCA.
    if hasNode(root, n1) and 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)

    return ans


def lca(root, n1, n2):
    ans = findLca(root, n1, n2, (None, -1), 0)
    return ans[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 = 7
    n2 = 8

    print(lca(root, n1, n2).data)
C#
using System;

class Node {
    public int data;
    public Node left, right;

    public Node(int value) {
        data = value;
        left = right = null;
    }
}

class GFG {

    static bool hasNode(Node root, int value) {
        if (root == null)
            return false;

        return root.data == value ||
               hasNode(root.left, value) ||
               hasNode(root.right, value);
    }

    static void findLca(Node root, int n1, int n2,
                        ref Node ans, int depth, ref 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, ref ans, depth + 1, ref bestDepth);
        findLca(root.right, n1, n2, ref ans, depth + 1, ref bestDepth);
    }

    static Node lca(Node root, int n1, int n2) {
        Node ans = null;
        int bestDepth = -1;

        findLca(root, n1, n2, ref ans, 0, ref bestDepth);

        return ans;
    }

    static void Main() {
        Node root = new Node(1);
        root.left = new Node(2);
        root.right = new Node(3);
        root.right.left = new Node(6);
        root.right.right = new Node(7);
        root.right.left.left = new Node(8);

        int n1 = 7;
        int n2 = 8;

        Console.WriteLine(lca(root, n1, n2).data);
    }
}
JavaScript
class Node {
    constructor(value) {
        this.data = value;
        this.left = null;
        this.right = null;
    }
}

function hasNode(root, value) {
    if (root === null)
        return false;

    return root.data === value ||
           hasNode(root.left, value) ||
           hasNode(root.right, value);
}

function findLca(root, n1, n2, ans, depth) {
    if (root === null)
        return ans;

    // 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);

    return ans;
}

function lca(root, n1, n2) {
    const ans = findLca(root, n1, n2, [null, -1], 0);
    return ans[0];
}

// Driver Code
const root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.right.left = new Node(6);
root.right.right = new Node(7);
root.right.left.left = new Node(8);

const n1 = 7;
const n2 = 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:

111

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>
using namespace std;

struct Node {
    int data;
    Node* left;
    Node* right;

    Node(int value) {
        data = value;
        left = right = nullptr;
    }
};

bool findPath(Node* root, int value, vector<Node*>& path) {
    if (root == nullptr)
        return false;

    path.push_back(root);

    if (root->data == value)
        return true;

    if (findPath(root->left, value, path) ||
        findPath(root->right, value, path))
        return true;

    path.pop_back();
    return false;
}

Node* lca(Node* root, int n1, int n2) {
    vector<Node*> path1, path2;

    findPath(root, n1, path1);
    findPath(root, n2, path2);

    Node* ans = nullptr;

    // Compare both paths to find the last common node.
    int i = 0;
    while (i < path1.size() && i < path2.size() &&
           path1[i] == path2[i]) {
        ans = path1[i];
        i++;
    }

    // Return the last common node as the LCA.
    return ans;
}

int main() {
    Node* root = new Node(1);
    root->left = new Node(2);
    root->right = new Node(3);
    root->right->left = new Node(6);
    root->right->right = new Node(7);
    root->right->left->left = new Node(8);

    int n1 = 7;
    int n2 = 8;

    Node* ans = lca(root, n1, n2);

    cout << ans->data << endl;

    return 0;
}
C
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

struct Node {
    int data;
    struct Node* left;
    struct Node* right;
};

struct Node* newNode(int value) {
    struct Node* node = (struct Node*)malloc(sizeof(struct Node));
    node->data = value;
    node->left = node->right = NULL;
    return node;
}

bool findPath(struct Node* root, int value,
              struct Node** path, int* pathLen) {
    if (root == NULL)
        return false;

    path[(*pathLen)++] = root;

    if (root->data == value)
        return true;

    if (findPath(root->left, value, path, pathLen) ||
        findPath(root->right, value, path, pathLen))
        return true;

    (*pathLen)--;
    return false;
}

struct Node* lca(struct Node* root, int n1, int n2) {
    struct Node* path1[100];
    struct Node* path2[100];

    int len1 = 0;
    int len2 = 0;

    findPath(root, n1, path1, &len1);
    findPath(root, n2, path2, &len2);

    struct Node* ans = NULL;

    // Compare both paths to find the last common node.
    int i = 0;
    while (i < len1 && i < len2 && path1[i] == path2[i]) {
        ans = path1[i];
        i++;
    }

    // Return the last common node as the LCA.
    return ans;
}

int main() {
    struct 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);

    int n1 = 7;
    int n2 = 8;

    struct Node* ans = lca(root, n1, n2);

    printf("%d\n", ans->data);

    return 0;
}
Java
import java.util.ArrayList;

class Node {
    int data;
    Node left, right;

    Node(int value) {
        data = value;
        left = right = null;
    }
}

class GFG {

    static boolean findPath(Node root, int value,
                            ArrayList<Node> path) {
        if (root == null)
            return false;

        path.add(root);

        if (root.data == value)
            return true;

        if (findPath(root.left, value, path) ||
            findPath(root.right, value, path))
            return true;

        path.remove(path.size() - 1);
        return false;
    }

    static Node lca(Node root, int n1, int n2) {
        ArrayList<Node> path1 = new ArrayList<>();
        ArrayList<Node> path2 = new ArrayList<>();

        findPath(root, n1, path1);
        findPath(root, n2, path2);

        Node ans = null;

        // Compare both paths to find the last common node.
        int i = 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.
        return ans;
    }

    public static void main(String[] args) {
        Node root = new Node(1);
        root.left = new Node(2);
        root.right = new Node(3);
        root.right.left = new Node(6);
        root.right.right = new Node(7);
        root.right.left.left = new Node(8);

        int n1 = 7;
        int n2 = 8;

        Node ans = lca(root, n1, n2);

        System.out.println(ans.data);
    }
}
Python
class Node:
    def __init__(self, value):
        self.data = value
        self.left = None
        self.right = None


def findPath(root, value, path):
    if root is None:
        return False

    path.append(root)

    if root.data == value:
        return True

    if (findPath(root.left, value, path) or
            findPath(root.right, value, path)):
        return True

    path.pop()
    return False


def lca(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 = 0
    while (i < len(path1) and i < len(path2) and
           path1[i] is path2[i]):
        ans = path1[i]
        i += 1

    # Return the last common node as the LCA.
    return ans


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 = 7
    n2 = 8

    ans = lca(root, n1, n2)

    print(ans.data)
C#
using System;
using System.Collections.Generic;

class Node {
    public int data;
    public Node left, right;

    public Node(int value) {
        data = value;
        left = right = null;
    }
}

class GFG {

    static bool findPath(Node root, int value,
                         List<Node> path) {
        if (root == null)
            return false;

        path.Add(root);

        if (root.data == value)
            return true;

        if (findPath(root.left, value, path) ||
            findPath(root.right, value, path))
            return true;

        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>();

        findPath(root, n1, path1);
        findPath(root, n2, path2);

        Node ans = null;

        // Compare both paths to find the last common node.
        int i = 0;
        while (i < path1.Count && i < path2.Count &&
               path1[i] == path2[i]) {
            ans = path1[i];
            i++;
        }

        // Return the last common node as the LCA.
        return ans;
    }

    static void Main() {
        Node root = new Node(1);
        root.left = new Node(2);
        root.right = new Node(3);
        root.right.left = new Node(6);
        root.right.right = new Node(7);
        root.right.left.left = new Node(8);

        int n1 = 7;
        int n2 = 8;

        Node ans = lca(root, n1, n2);

        Console.WriteLine(ans.data);
    }
}
JavaScript
class Node {
    constructor(value) {
        this.data = value;
        this.left = null;
        this.right = null;
    }
}

function findPath(root, value, path) {
    if (root === null)
        return false;

    path.push(root);

    if (root.data === value)
        return true;

    if (findPath(root.left, value, path) ||
        findPath(root.right, value, path))
        return true;

    path.pop();
    return false;
}

function lca(root, n1, n2) {
    const path1 = [];
    const path2 = [];

    findPath(root, n1, path1);
    findPath(root, n2, path2);

    let ans = null;

    // Compare both paths to find the last common node.
    let i = 0;
    while (i < path1.length && i < path2.length &&
           path1[i] === path2[i]) {
        ans = path1[i];
        i++;
    }

    // Return the last common node as the LCA.
    return ans;
}

// Driver Code
const root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.right.left = new Node(6);
root.right.right = new Node(7);
root.right.left.left = new Node(8);

const n1 = 7;
const n2 = 8;

const ans = 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>
using namespace std;

class Node {
public:
    int data;
    Node *left, *right;

    Node(int value) {
        data = value;
        left = right = nullptr;
    }
};

Node* lca(Node* root, int n1, int n2) {
    if (root == nullptr)
        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 subtrees return a node, current root is the LCA.
    if (leftLca != nullptr && rightLca != nullptr)
        return root;

    return leftLca != nullptr ? leftLca : rightLca;
}

int main() {
    Node* root = new Node(1);
    root->left = new Node(2);
    root->right = new Node(3);
    root->right->left = new Node(6);
    root->right->right = new Node(7);
    root->right->left->left = new Node(8);

    int n1 = 7;
    int n2 = 8;

    Node* ans = lca(root, n1, n2);

    cout << ans->data << endl;

    return 0;
}
C
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

struct Node {
    int data;
    struct Node* left;
    struct Node* right;
};

struct Node* newNode(int value) {
    struct Node* node = (struct Node*)malloc(sizeof(struct Node));
    node->data = value;
    node->left = NULL;
    node->right = NULL;
    return node;
}

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->data == n1 || root->data == n2)
        return root;

    struct Node* leftLca = lca(root->left, n1, n2);
    struct Node* rightLca = lca(root->right, n1, n2);

    // If both subtrees return a node, current root is the LCA.
    if (leftLca != NULL && rightLca != NULL)
        return root;

    return leftLca != NULL ? leftLca : rightLca;
}

int main() {
    struct 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);

    int n1 = 7;
    int n2 = 8;

    struct Node* ans = lca(root, n1, n2);

    printf("%d\n", ans->data);

    return 0;
}
Java
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) {
        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 subtrees return a node, current root is the LCA.
        if (leftLca != null && rightLca != null)
            return root;

        return leftLca != null ? leftLca : rightLca;
    }

    public static void main(String[] args) {
        Node root = new Node(1);
        root.left = new Node(2);
        root.right = new Node(3);
        root.right.left = new Node(6);
        root.right.right = new Node(7);
        root.right.left.left = new Node(8);

        int n1 = 7;
        int n2 = 8;

        Node ans = lca(root, n1, n2);

        System.out.println(ans.data);
    }
}
Python
class Node:
    def __init__(self, value):
        self.data = value
        self.left = None
        self.right = None


def lca(root, n1, n2):
    if root is None:
        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 subtrees return a node, current root is the LCA.
    if leftLca is not None and rightLca is not None:
        return root

    return leftLca if leftLca is not None else rightLca


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 = 7
    n2 = 8

    ans = lca(root, n1, n2)

    print(ans.data)
C#
using System;

class Node {
    public int data;
    public Node left, right;

    public Node(int value) {
        data = value;
        left = 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 subtrees return a node, current root is the LCA.
        if (leftLca != null && rightLca != null)
            return root;

        return leftLca != null ? leftLca : rightLca;
    }

    static void Main() {
        Node root = new Node(1);
        root.left = new Node(2);
        root.right = new Node(3);
        root.right.left = new Node(6);
        root.right.right = new Node(7);
        root.right.left.left = new Node(8);

        int n1 = 7;
        int n2 = 8;

        Node ans = lca(root, n1, n2);

        Console.WriteLine(ans.data);
    }
}
JavaScript
class Node {
    constructor(value) {
        this.data = value;
        this.left = null;
        this.right = null;
    }
}

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;

    const leftLca = lca(root.left, n1, n2);
    const rightLca = lca(root.right, n1, n2);

    // If both subtrees return a node, current root is the LCA.
    if (leftLca !== null && rightLca !== null)
        return root;

    return leftLca !== null ? leftLca : rightLca;
}

// Driver Code
const root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.right.left = new Node(6);
root.right.right = new Node(7);
root.right.left.left = new Node(8);

const n1 = 7;
const n2 = 8;

const ans = lca(root, n1, n2);

console.log(ans.data);

Output
3
Comment