Open In App

Find LCA in Binary Tree using RMQ

Last Updated : 31 Jul, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

The article describes an approach to solving the problem of finding the LCA of two nodes in a tree by reducing it to an RMQ problem.

The Lowest Common Ancestor (LCA) of two nodes u and v in a rooted tree T is defined as the node located farthest from the root that has both u and v as descendants.
For example, in the below diagram, the LCA of node 4 and node 9 is node 2.  

lca

There can be many approaches to solving the LCA problem. The approaches differ in their time and space complexities. Here is a link to a couple of them (these do not involve a reduction to RMQ).

Range Minimum Query (RMQ) is used on arrays to find the position of an element with the minimum value between two specified indices. Different approaches to solving RMQ have been discussed here and here. In this article, the Segment Tree-based approach is discussed. With a segment tree, preprocessing time is O(n) and the time for range minimum query is O(Logn). The extra space required is O(n) to store the segment tree.

Reduction of LCA to RMQ: 

The idea is to traverse the tree starting from the root by an Euler tour (traversal without lifting a pencil), which is a DFS-type traversal with preorder traversal characteristics. 
 

eulertour

Observation

The LCA of nodes 4 and 9 is node 2, which happens to be the node closest to the root amongst all those encountered between the visits of 4 and 9 during a DFS of T. This observation is the key to the reduction. Let’s rephrase: Our node is the node at the smallest level and the only node at that level amongst all the nodes that occur between consecutive occurrences (any) of u and v in the Euler tour of T.

We require three arrays for implementation: 

  1. Nodes visited in order of Euler tour of T
  2. The level of each node visited in the Euler tour of T
  3. Index of the first occurrence of a node in Euler tour of T (since any occurrence would be good, let’s track the first one)

lca2

Algorithm: 

  1. Do a Euler tour on the tree, and fill the euler, level and first occurrence arrays.
  2. Using the first occurrence array, get the indices corresponding to the two nodes which will be the corners of the range in the level array that is fed to the RMQ algorithm for the minimum value.
  3. Once the algorithm return the index of the minimum level in the range, we use it to determine the LCA using Euler tour array.

Below is the implementation of the above algorithm.

C++




/* C++ Program to find LCA of u and v by reducing the problem to RMQ */
#include<bits/stdc++.h>
#define V 9               // number of nodes in input tree
 
int euler[2*V - 1];       // For Euler tour sequence
int level[2*V - 1];       // Level of nodes in tour sequence
int firstOccurrence[V+1]; // First occurrences of nodes in tour
int ind;                  // Variable to fill-in euler and level arrays
 
// A Binary Tree node
struct Node
{
    int key;
    struct Node *left, *right;
};
 
// Utility function creates a new binary tree node with given key
Node * newNode(int k)
{
    Node *temp = new Node;
    temp->key = k;
    temp->left = temp->right = NULL;
    return temp;
}
 
// log base 2 of x
int Log2(int x)
{
    int ans = 0 ;
    while (x>>=1) ans++;
    return ans ;
}
 
/*  A recursive function to get the minimum value in a given range
     of array indexes. The following are parameters for this function.
 
    st    --> Pointer to segment tree
    index --> Index of current node in the segment tree. Initially
              0 is passed as root is always at index 0
    ss & se  --> Starting and ending indexes of the segment represented
                  by current node, i.e., st[index]
    qs & qe  --> Starting and ending indexes of query range */
int RMQUtil(int index, int ss, int se, int qs, int qe, int *st)
{
    // If segment of this node is a part of given range, then return
    //  the min of the segment
    if (qs <= ss && qe >= se)
        return st[index];
 
    // If segment of this node is outside the given range
    else if (se < qs || ss > qe)
        return -1;
 
    // If a part of this segment overlaps with the given range
    int mid = (ss + se)/2;
 
    int q1 = RMQUtil(2*index+1, ss, mid, qs, qe, st);
    int q2 = RMQUtil(2*index+2, mid+1, se, qs, qe, st);
 
    if (q1==-1) return q2;
 
    else if (q2==-1) return q1;
 
    return (level[q1] < level[q2]) ? q1 : q2;
}
 
// Return minimum of elements in range from index qs (query start) to
// qe (query end).  It mainly uses RMQUtil()
int RMQ(int *st, int n, int qs, int qe)
{
    // Check for erroneous input values
    if (qs < 0 || qe > n-1 || qs > qe)
    {
        printf("Invalid Input");
        return -1;
    }
 
    return RMQUtil(0, 0, n-1, qs, qe, st);
}
 
// A recursive function that constructs Segment Tree for array[ss..se].
// si is index of current node in segment tree st
void constructSTUtil(int si, int ss, int se, int arr[], int *st)
{
    // If there is one element in array, store it in current node of
    // segment tree and return
    if (ss == se)st[si] = ss;
 
    else
    {
        // If there are more than one elements, then recur for left and
        // right subtrees and store the minimum of two values in this node
        int mid = (ss + se)/2;
        constructSTUtil(si*2+1, ss, mid, arr, st);
        constructSTUtil(si*2+2, mid+1, se, arr, st);
 
        if (arr[st[2*si+1]] < arr[st[2*si+2]])
            st[si] = st[2*si+1];
        else
            st[si] = st[2*si+2];
    }
}
 
/* Function to construct segment tree from given array. This function
   allocates memory for segment tree and calls constructSTUtil() to
   fill the allocated memory */
int *constructST(int arr[], int n)
{
    // Allocate memory for segment tree
 
    // Height of segment tree
    int x = Log2(n)+1;
 
    // Maximum size of segment tree
    int max_size = 2*(1<<x) - 1;  //  2*pow(2,x) -1
 
    int *st = new int[max_size];
 
    // Fill the allocated memory st
    constructSTUtil(0, 0, n-1, arr, st);
 
    // Return the constructed segment tree
    return st;
}
 
// Recursive version of the Euler tour of T
void eulerTour(Node *root, int l)
{
    /* if the passed node exists */
    if (root)
    {
        euler[ind] = root->key; // insert in euler array
        level[ind] = l;         // insert l in level array
        ind++;                  // increment index
 
        /* if unvisited, mark first occurrence */
        if (firstOccurrence[root->key] == -1)
            firstOccurrence[root->key] = ind-1;
 
        /* tour left subtree if exists, and remark euler
           and level arrays for parent on return */
        if (root->left)
        {
            eulerTour(root->left, l+1);
            euler[ind]=root->key;
            level[ind] = l;
            ind++;
        }
 
        /* tour right subtree if exists, and remark euler
           and level arrays for parent on return */
        if (root->right)
        {
            eulerTour(root->right, l+1);
            euler[ind]=root->key;
            level[ind] = l;
            ind++;
        }
    }
}
 
// Returns LCA of nodes n1, n2 (assuming they are
//  present in the tree)
int findLCA(Node *root, int u, int v)
{
    /* Mark all nodes unvisited.  Note that the size of
        firstOccurrence is 1 as node values which vary from
        1 to 9 are used as indexes */
    memset(firstOccurrence, -1, sizeof(int)*(V+1));
 
    /* To start filling euler and level arrays from index 0 */
    ind = 0;
 
    /* Start Euler tour with root node on level 0 */
    eulerTour(root, 0);
 
    /* construct segment tree on level array */
    int *st = constructST(level, 2*V-1);
 
    /* If v before u in Euler tour.  For RMQ to work, first
       parameter 'u' must be smaller than second 'v' */
    if (firstOccurrence[u]>firstOccurrence[v])
       std::swap(u, v);
 
    // Starting and ending indexes of query range
    int qs = firstOccurrence[u];
    int qe = firstOccurrence[v];
 
    // query for index of LCA in tour
    int index = RMQ(st, 2*V-1, qs, qe);
 
    /* return LCA node */
    return euler[index];
}
 
// Driver program to test above functions
int main()
{
    // Let us create the Binary Tree as shown in the diagram.
    Node * root = newNode(1);
    root->left = newNode(2);
    root->right = newNode(3);
    root->left->left = newNode(4);
    root->left->right = newNode(5);
    root->right->left = newNode(6);
    root->right->right = newNode(7);
    root->left->right->left = newNode(8);
    root->left->right->right = newNode(9);
 
    int u = 4, v = 9;
    printf("The LCA of node %d and node %d is node %d.\n",
            u, v, findLCA(root, u, v));
    return 0;
}


Java




// Java program to find LCA of u and v by reducing problem to RMQ
  
import java.util.*;
  
// A binary tree node
class Node
{
    Node left, right;
    int data;
  
    Node(int item)
    {
        data = item;
        left = right = null;
    }
}
  
class St_class
{
    int st;
    int stt[] = new int[10000];
}
  
class BinaryTree
{
    Node root;
    int v = 9; // v is the highest value of node in our tree
    int euler[] = new int[2 * v - 1]; // for euler tour sequence
    int level[] = new int[2 * v - 1]; // level of nodes in tour sequence
    int f_occur[] = new int[2 * v - 1]; // to store 1st occurrence of nodes
    int fill; // variable to fill euler and level arrays
    St_class sc = new St_class();
  
    // log base 2 of x
    int Log2(int x)
    {
        int ans = 0;
        int y = x >>= 1;
        while (y-- != 0)
            ans++;
        return ans;
    }
  
    int swap(int a, int b)
    {
        return a;
    }
  
    /*  A recursive function to get the minimum value in a given range
     of array indexes. The following are parameters for this function.
   
     st    --> Pointer to segment tree
     index --> Index of current node in the segment tree. Initially
     0 is passed as root is always at index 0
     ss & se  --> Starting and ending indexes of the segment represented
     by current node, i.e., st[index]
     qs & qe  --> Starting and ending indexes of query range */
    int RMQUtil(int index, int ss, int se, int qs, int qe, St_class st)
    {
        // If segment of this node is a part of given range, then return
        //  the min of the segment
        if (qs <= ss && qe >= se)
            return st.stt[index];
  
        // If segment of this node is outside the given range
        else if (se < qs || ss > qe)
            return -1;
  
        // If a part of this segment overlaps with the given range
        int mid = (ss + se) / 2;
  
        int q1 = RMQUtil(2 * index + 1, ss, mid, qs, qe, st);
        int q2 = RMQUtil(2 * index + 2, mid + 1, se, qs, qe, st);
  
        if (q1 == -1)
            return q2;
        else if (q2 == -1)
            return q1;
  
        return (level[q1] < level[q2]) ? q1 : q2;
    }
  
    // Return minimum of elements in range from index qs (query start) to
    // qe (query end).  It mainly uses RMQUtil()
    int RMQ(St_class st, int n, int qs, int qe)
    {
        // Check for erroneous input values
        if (qs < 0 || qe > n - 1 || qs > qe)
        {
            System.out.println("Invalid input");
            return -1;
        }
  
        return RMQUtil(0, 0, n - 1, qs, qe, st);
    }
  
    // A recursive function that constructs Segment Tree for array[ss..se].
    // si is index of current node in segment tree st
    void constructSTUtil(int si, int ss, int se, int arr[], St_class st)
    {
        // If there is one element in array, store it in current node of
        // segment tree and return
        if (ss == se)
            st.stt[si] = ss;
        else
        {
            // If there are more than one elements, then recur for left and
            // right subtrees and store the minimum of two values in this node
            int mid = (ss + se) / 2;
            constructSTUtil(si * 2 + 1, ss, mid, arr, st);
            constructSTUtil(si * 2 + 2, mid + 1, se, arr, st);
  
            if (arr[st.stt[2 * si + 1]] < arr[st.stt[2 * si + 2]])
                st.stt[si] = st.stt[2 * si + 1];
            else
                st.stt[si] = st.stt[2 * si + 2];
        }
    }
  
    /* Function to construct segment tree from given array. This function
     allocates memory for segment tree and calls constructSTUtil() to
     fill the allocated memory */
    int constructST(int arr[], int n)
    {
        // Allocate memory for segment tree
        // Height of segment tree
        int x = Log2(n) + 1;
          
        // Maximum size of segment tree
        int max_size = 2 * (1 << x) - 1//  2*pow(2,x) -1
  
        sc.stt = new int[max_size];
  
        // Fill the allocated memory st
        constructSTUtil(0, 0, n - 1, arr, sc);
          
        // Return the constructed segment tree
        return sc.st;
    }
  
    // Recursive version of the Euler tour of T
    void eulerTour(Node node, int l)
    {
        /* if the passed node exists */
        if (node != null)
        {
            euler[fill] = node.data; // insert in euler array
            level[fill] = l;         // insert l in level array
            fill++;                  // increment index
  
            /* if unvisited, mark first occurrence */
            if (f_occur[node.data] == -1)
                f_occur[node.data] = fill - 1;
  
            /* tour left subtree if exists, and remark euler
               and level arrays for parent on return */
            if (node.left != null)
            {
                eulerTour(node.left, l + 1);
                euler[fill] = node.data;
                level[fill] = l;
                fill++;
            }
  
            /* tour right subtree if exists, and remark euler
               and level arrays for parent on return */
            if (node.right != null)
            {
                eulerTour(node.right, l + 1);
                euler[fill] = node.data;
                level[fill] = l;
                fill++;
            }
        }
    }
  
    // returns LCA of node n1 and n2 assuming they are present in tree
    int findLCA(Node node, int u, int v)
    {
        /* Mark all nodes unvisited.  Note that the size of
           firstOccurrence is 1 as node values which vary from
           1 to 9 are used as indexes */
        Arrays.fill(f_occur, -1);
  
        /* To start filling euler and level arrays from index 0 */
        fill = 0;
  
        /* Start Euler tour with root node on level 0 */
        eulerTour(root, 0);
         
        /* construct segment tree on level array */
        sc.st = constructST(level, 2 * v - 1);
          
        /* If v before u in Euler tour.  For RMQ to work, first
         parameter 'u' must be smaller than second 'v' */
        if (f_occur[u] > f_occur[v])
            u = swap(u, u = v);
  
        // Starting and ending indexes of query range
        int qs = f_occur[u];
        int qe = f_occur[v];
  
        // query for index of LCA in tour
        int index = RMQ(sc, 2 * v - 1, qs, qe);
  
        /* return LCA node */
        return euler[index];
  
    }
  
    // Driver program to test above functions
    public static void main(String args[])
    {
        BinaryTree tree = new BinaryTree();
  
        // Let us create the Binary Tree as shown in the diagram.
        tree.root = new Node(1);
        tree.root.left = new Node(2);
        tree.root.right = new Node(3);
        tree.root.left.left = new Node(4);
        tree.root.left.right = new Node(5);
        tree.root.right.left = new Node(6);
        tree.root.right.right = new Node(7);
        tree.root.left.right.left = new Node(8);
        tree.root.left.right.right = new Node(9);
  
        int u = 4, v = 9;
        System.out.println("The LCA of node " + u + " and " + v + " is "
                + tree.findLCA(tree.root, u, v));
    }
  
}
 
// This code has been contributed by Mayank Jaiswal


Python3




# Python3 program to find LCA of u and v by
# reducing the problem to RMQ
from math import log2, floor
from typing import List
 
class Node:
     
    def __init__(self, val: int):
         
        self.val, self.left, self.right = val, None, None
 
class BinaryTree:
     
    def __init__(self, root: Node):
         
        self.root = root
        self.val_max = self._get_max_val()
        self.euler = [0] * (2 * self.val_max - 1)
        self.level = [0] * (2 * self.val_max - 1)
        self.f_occur = [-1] * (self.val_max + 1)
        self.fill = 0
        self.segment_tree = []
 
    def _get_max_val(self):
         
        stack = [self.root]
        max_val = -1
         
        while stack:
            x = stack.pop()
            if x.val > max_val:
                max_val = x.val
            if x.left:
                stack.append(x.left)
            if x.right:
                stack.append(x.right)
                 
        return max_val
    ''' A recursive function to get the minimum value in a given range
     of array indexes. The following are parameters for this function.
      
    st    --> Pointer to segment tree
    index --> Index of current node in the segment tree. Initially
              0 is passed as root is always at index 0
    ss & se  --> Starting and ending indexes of the segment represented
                  by current node, i.e., st[index]
    qs & qe  --> Starting and ending indexes of query range '''
    def rmq_util(self, index, ss, se, qs, qe) -> int:
         
        # If segment of this node is part of given range
        # then return the min of the segment
        if qs <= ss and qe >= se:
            return self.segment_tree[index]
 
        # If segment of this node is outside
        # the given range
        elif se < qs or ss > qe:
            return -1
 
        # If part of this segment overlaps with
        # given range
        mid = (ss + se) // 2
         
        q1 = self.rmq_util(2 * index + 1,
                           ss, mid, qs, qe)
        q2 = self.rmq_util(2 * index + 2, mid + 1,
                           se, qs, qe)
                            
        if q1 == -1:
            return q2
        if q2 == -1:
            return q1
        return (q1 if self.level[q1] <
                      self.level[q2] else q2)
                       
    # Return minimum of elements in range from
    # index qs (query start) to  qe (query end). 
    # It mainly uses rmq_util()
    def rmq(self, n: int, qs: int, qe: int) -> int:
         
        if qs < 0 or qe > n - 1 or qs > qe:
            print('invalid input')
            return -1
             
        return self.rmq_util(0, 0, n - 1, qs, qe)
         
    # A recursive function that constructs Segment
    # Tree for array[ss..se]. si is index of
    # current node in segment tree st
    def construct_segment_tree_util(self, si, ss,
                                    se, arr):
 
        # If  there is one element in array,
        # store it in current node of segment tree
        # and return
        if ss == se:
            self.segment_tree[si] = ss
        else:
 
            # If there are more than one elements,
            # then recur for left and right subtrees and
            # store the min of two values in this node
            mid = (ss + se) // 2
            index_left, index_right = si * 2 + 1, si * 2 + 2
            self.construct_segment_tree_util(
                index_left, ss, mid, arr)
            self.construct_segment_tree_util(
                index_right, mid+1, se, arr)
            
            if (arr[self.segment_tree[index_left]] <
                arr[self.segment_tree[index_right]]):
                self.segment_tree[si] = self.segment_tree[index_left]
            else:
                self.segment_tree[si] = self.segment_tree[index_right]
     
    # Function to construct segment tree from given
    # array. This function allocates memory for segment
    # tree and calls construct_segment_tree_util()
    # to fill the allocated memory
    def construct_segment_tree(self, arr: List, n: int):
         
        # Height of segment tree
        x = floor(log2(n) + 1)
         
        # Maximum size of segment tree
        max_size = 2 * (1 << x) - 1      # 2*pow(2,x) -1
         
        self.segment_tree = [0] * max_size
         
        # Fill the allocated memory st
        self.construct_segment_tree_util(
            0, 0, n - 1, arr)
     
    # Recursive version of the Euler tour of T
    def euler_tour(self, node: Node, lev: int):
         
        # If the passed node exists
        if node is not None:
            self.euler[self.fill] = node.val
            self.level[self.fill] = lev
            self.fill += 1
             
            # If unvisited, mark first occurrence
            if self.f_occur[node.val] == -1:
                self.f_occur[node.val] = self.fill - 1
 
            # Tour left subtree if exists and remark
            # euler and level arrays for parent on
            # return
            if node.left is not None:
                self.euler_tour(node.left, lev + 1)
                self.euler[self.fill] = node.val
                self.level[self.fill] = lev
                self.fill += 1
 
            # Tour right subtree if exists and
            # remark euler and level arrays for
            # parent on return
            if node.right is not None:
                self.euler_tour(node.right, lev + 1)
                self.euler[self.fill] = node.val
                self.level[self.fill] = lev
                self.fill += 1
     
    # Returns LCA of nodes n1, n2 (assuming they are
    # present in the tree)
    def find_lca(self, u: int, v: int):
         
        # Start euler tour with root node on level 0
        self.euler_tour(self.root, 0)
         
        # Construct segment tree on level array
        self.construct_segment_tree(self.level,
                                2 * self.val_max - 1)
                                 
        # For rmq to work, u must be smaller than v
        if self.f_occur[u] > self.f_occur[v]:
            u, v = v, u
             
        # Start and end of query range
        qs = self.f_occur[u]
        qe = self.f_occur[v]
         
        # Query for index of lca in tour
        index = self.rmq(2 * self.val_max - 1, qs, qe)
         
        # Return lca node
        return self.euler[index]
 
# Driver code
if __name__ == "__main__":
     
    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.left.right.left = Node(8)
    root.left.right.right = Node(9)
 
    tree = BinaryTree(root)
    u, v = 4, 9
    print('The lca of node {} and {} is node {}'.format(
        u, v, tree.find_lca(u, v)))
 
# This code is contributed by Rajat Srivastava


C#




// C# program to find LCA of u and
// v by reducing problem to RMQ
using System;
 
// A binary tree node
class Node
{
    public Node left, right;
    public int data;
 
    public Node(int item)
    {
        data = item;
        left = right = null;
    }
}
 
class St_class
{
    public int st;
    public int []stt = new int[10000];
}
 
public class BinaryTree
{
    Node root;
    static int v = 9; // v is the highest value of node in our tree
    int []euler = new int[2 * v - 1]; // for euler tour sequence
    int []level = new int[2 * v - 1]; // level of nodes in tour sequence
    int []f_occur = new int[2 * v - 1]; // to store 1st occurrence of nodes
    int fill; // variable to fill euler and level arrays
    St_class sc = new St_class();
 
    // log base 2 of x
    int Log2(int x)
    {
        int ans = 0;
        int y = x >>= 1;
        while (y-- != 0)
            ans++;
        return ans;
    }
 
    int swap(int a, int b)
    {
        return a;
    }
 
    /* A recursive function to get
    the minimum value in a given range
    of array indexes. The following
    are parameters for this function.
     
    st --> Pointer to segment tree
    index --> Index of current node
    in the segment tree. Initially
    0 is passed as root is always at index 0
    ss & se --> Starting and ending
    indexes of the segment represented
    by current node, i.e., st[index]
    qs & qe --> Starting and ending
    indexes of query range */
    int RMQUtil(int index, int ss, int se,
                    int qs, int qe, St_class st)
    {
        // If segment of this node is a part
        // of given range, then return
        // the min of the segment
        if (qs <= ss && qe >= se)
            return st.stt[index];
 
        // If segment of this node is
        // outside the given range
        else if (se < qs || ss > qe)
            return -1;
 
        // If a part of this segment
        // overlaps with the given range
        int mid = (ss + se) / 2;
 
        int q1 = RMQUtil(2 * index + 1,
                        ss, mid, qs, qe, st);
        int q2 = RMQUtil(2 * index + 2,
                        mid + 1, se, qs, qe, st);
 
        if (q1 == -1)
            return q2;
        else if (q2 == -1)
            return q1;
 
        return (level[q1] < level[q2]) ? q1 : q2;
    }
 
    // Return minimum of elements in
    // range from index qs (query start) to
    // qe (query end). It mainly uses RMQUtil()
    int RMQ(St_class st, int n, int qs, int qe)
    {
        // Check for erroneous input values
        if (qs < 0 || qe > n - 1 || qs > qe)
        {
            Console.WriteLine("Invalid input");
            return -1;
        }
 
        return RMQUtil(0, 0, n - 1, qs, qe, st);
    }
 
    // A recursive function that constructs
    // Segment Tree for array[ss..se].
    // si is index of current node in segment tree st
    void constructSTUtil(int si, int ss, int se,
                        int []arr, St_class st)
    {
        // If there is one element in array,
        // store it in current node of
        // segment tree and return
        if (ss == se)
            st.stt[si] = ss;
        else
        {
            // If there are more than one elements,
            // then recur for left and right subtrees
            // and store the minimum of two values in this node
            int mid = (ss + se) / 2;
            constructSTUtil(si * 2 + 1, ss, mid, arr, st);
            constructSTUtil(si * 2 + 2, mid + 1, se, arr, st);
 
            if (arr[st.stt[2 * si + 1]] < arr[st.stt[2 * si + 2]])
                st.stt[si] = st.stt[2 * si + 1];
            else
                st.stt[si] = st.stt[2 * si + 2];
        }
    }
 
    /* Function to construct segment tree
    from given array. This function
    allocates memory for segment tree
    and calls constructSTUtil() to
    fill the allocated memory */
    int constructST(int []arr, int n)
    {
        // Allocate memory for segment tree
        // Height of segment tree
        int x = Log2(n) + 1;
         
        // Maximum size of segment tree
        int max_size = 2 * (1 << x) - 1; // 2*pow(2,x) -1
 
        sc.stt = new int[max_size];
 
        // Fill the allocated memory st
        constructSTUtil(0, 0, n - 1, arr, sc);
         
        // Return the constructed segment tree
        return sc.st;
    }
 
    // Recursive version of the Euler tour of T
    void eulerTour(Node node, int l)
    {
        /* if the passed node exists */
        if (node != null)
        {
            euler[fill] = node.data; // insert in euler array
            level[fill] = l;         // insert l in level array
            fill++;                 // increment index
 
            /* if unvisited, mark first occurrence */
            if (f_occur[node.data] == -1)
                f_occur[node.data] = fill - 1;
 
            /* tour left subtree if exists,
                and remark euler and level
                arrays for parent on return */
            if (node.left != null)
            {
                eulerTour(node.left, l + 1);
                euler[fill] = node.data;
                level[fill] = l;
                fill++;
            }
 
            /* tour right subtree if exists, and remark euler
            and level arrays for parent on return */
            if (node.right != null)
            {
                eulerTour(node.right, l + 1);
                euler[fill] = node.data;
                level[fill] = l;
                fill++;
            }
        }
    }
 
    // returns LCA of node n1 and n2
    // assuming they are present in tree
    int findLCA(Node node, int u, int v)
    {
        /* Mark all nodes unvisited. Note
         that the size of firstOccurrence
         is 1 as node values which
         vary from 1 to 9 are used as indexes */
        //Arrays.fill(f_occur, -1);
        for(int i = 0; i < f_occur.Length; i++)
            f_occur[i] = -1;
 
 
        /* To start filling euler and
        level arrays from index 0 */
        fill = 0;
 
        /* Start Euler tour with
        root node on level 0 */
        eulerTour(root, 0);
         
        /* construct segment tree on level array */
        sc.st = constructST(level, 2 * v - 1);
         
        /* If v before u in Euler tour.
        For RMQ to work, first parameter
        'u' must be smaller than
         second 'v' */
        if (f_occur[u] > f_occur[v])
            u = swap(u, u = v);
 
        // Starting and ending indexes of query range
        int qs = f_occur[u];
        int qe = f_occur[v];
 
        // query for index of LCA in tour
        int index = RMQ(sc, 2 * v - 1, qs, qe);
 
        /* return LCA node */
        return euler[index];
 
    }
 
    // Driver program to test above functions
    public static void Main(String []args)
    {
        BinaryTree tree = new BinaryTree();
 
        // Let us create the Binary Tree
        // as shown in the diagram.
        tree.root = new Node(1);
        tree.root.left = new Node(2);
        tree.root.right = new Node(3);
        tree.root.left.left = new Node(4);
        tree.root.left.right = new Node(5);
        tree.root.right.left = new Node(6);
        tree.root.right.right = new Node(7);
        tree.root.left.right.left = new Node(8);
        tree.root.left.right.right = new Node(9);
 
        int u = 4, v = 9;
        Console.WriteLine("The LCA of node " + u + " and " + v + " is "
                + tree.findLCA(tree.root, u, v));
    }
}
 
// This code is contributed by 29AjayKumar


Javascript




<script>
 
// JavaScript program to find LCA of u and v
// by reducing problem to RMQ
 
// A binary tree node
class Node
{
    constructor(item)
    {
        this.data=item;
        this.left = this.right = null;
    }
}
 
class St_class
{
    st;
    stt=new Array(10000);
}
 
let root;
// v is the highest value of node in our tree
let v = 9;
// for euler tour sequence
let euler = new Array(2 * v - 1);
// level of nodes in tour sequence
let level = new Array(2 * v - 1);
// to store 1st occurrence of nodes
let f_occur = new Array(2 * v - 1);
 
let fill; // variable to fill euler and level arrays
let sc = new St_class();
 
 // log base 2 of x
function Log2(x)
{
    let ans = 0;
        let y = x >>= 1;
        while (y-- != 0)
            ans++;
        return ans;
}
 
function swap(a,b)
{
    return a;
}
 
/*  A recursive function to get the
    minimum value in a given range
     of array indexes. The following
     are parameters for this function.
    
     st    --> Pointer to segment tree
     index --> Index of current node in
     the segment tree. Initially
     0 is passed as root is always at index 0
     ss & se  --> Starting and ending indexes
     of the segment represented
     by current node, i.e., st[index]
     qs & qe  --> Starting and ending indexes of query range */
function RMQUtil(index,ss,se,qs,qe,st)
{
    // If segment of this node is a part
    // of given range, then return
        //  the min of the segment
        if (qs <= ss && qe >= se)
            return st.stt[index];
   
        // If segment of this node is
        // outside the given range
        else if (se < qs || ss > qe)
            return -1;
   
        // If a part of this segment overlaps
        // with the given range
        let mid = Math.floor((ss + se) / 2);
   
        let q1 = RMQUtil(2 * index + 1, ss, mid, qs, qe, st);
        let q2 = RMQUtil(2 * index + 2, mid + 1, se, qs, qe, st);
   
        if (q1 == -1)
            return q2;
        else if (q2 == -1)
            return q1;
   
        return (level[q1] < level[q2]) ? q1 : q2;
}
 
// Return minimum of elements in range
// from index qs (query start) to
    // qe (query end).  It mainly uses RMQUtil()
function RMQ(st,n,qs,qe)
{
     // Check for erroneous input values
        if (qs < 0 || qe > n - 1 || qs > qe)
        {
            document.write("Invalid input");
            return -1;
        }
   
        return RMQUtil(0, 0, n - 1, qs, qe, st);
}
 
// A recursive function that constructs
// Segment Tree for array[ss..se].
    // si is index of current node in segment tree st
function constructSTUtil(si,ss,se,arr,st)
{
    // If there is one element in array,
    // store it in current node of
        // segment tree and return
        if (ss == se)
            st.stt[si] = ss;
        else
        {
            // If there are more than one elements,
            // then recur for left and
            // right subtrees and store the minimum
            // of two values in this node
            let mid = Math.floor((ss + se) / 2);
            constructSTUtil(si * 2 + 1, ss, mid, arr, st);
            constructSTUtil(si * 2 + 2, mid + 1, se, arr, st);
   
            if (arr[st.stt[2 * si + 1]] < arr[st.stt[2 * si + 2]])
                st.stt[si] = st.stt[2 * si + 1];
            else
                st.stt[si] = st.stt[2 * si + 2];
        }
}
 
/* Function to construct segment tree
     from given array. This function
     allocates memory for segment tree and
     calls constructSTUtil() to
     fill the allocated memory */
function constructST(arr,n)
{
    // Allocate memory for segment tree
        // Height of segment tree
        let x = Log2(n) + 1;
           
        // Maximum size of segment tree
        let max_size = 2 * (1 << x) - 1;  //  2*pow(2,x) -1
   
        sc.stt = new Array(max_size);
   
        // Fill the allocated memory st
        constructSTUtil(0, 0, n - 1, arr, sc);
           
        // Return the constructed segment tree
        return sc.st;
}
 
// Recursive version of the Euler tour of T
function eulerTour(node,l)
{
    /* if the passed node exists */
        if (node != null)
        {
            euler[fill] = node.data; // insert in euler array
            level[fill] = l;         // insert l in level array
            fill++;                  // increment index
   
            /* if unvisited, mark first occurrence */
            if (f_occur[node.data] == -1)
                f_occur[node.data] = fill - 1;
   
            /* tour left subtree if exists, and remark euler
               and level arrays for parent on return */
            if (node.left != null)
            {
                eulerTour(node.left, l + 1);
                euler[fill] = node.data;
                level[fill] = l;
                fill++;
            }
   
            /* tour right subtree if exists, and remark euler
               and level arrays for parent on return */
            if (node.right != null)
            {
                eulerTour(node.right, l + 1);
                euler[fill] = node.data;
                level[fill] = l;
                fill++;
            }
        }
}
 
// returns LCA of node n1 and n2
// assuming they are present in tree
function findLCA(node,u,v)
{
    /* Mark all nodes unvisited.  Note that the size of
           firstOccurrence is 1 as node values which vary from
           1 to 9 are used as indexes */
           for(let i=0;i<f_occur.length;i++)
           {
               f_occur[i]=-1;
           }
         
   
        /* To start filling euler and
        level arrays from index 0 */
        fill = 0;
   
        /* Start Euler tour with root node on level 0 */
        eulerTour(root, 0);
          
        /* construct segment tree on level array */
        sc.st = constructST(level, 2 * v - 1);
           
        /* If v before u in Euler tour.  For RMQ to work, first
         parameter 'u' must be smaller than second 'v' */
        if (f_occur[u] > f_occur[v])
            u = swap(u, u = v);
   
        // Starting and ending indexes of query range
        let qs = f_occur[u];
        let qe = f_occur[v];
   
        // query for index of LCA in tour
        let index = RMQ(sc, 2 * v - 1, qs, qe);
   
        /* return LCA node */
        return euler[index];
}
 
 // Driver program to test above functions
 
// Let us create the Binary Tree as shown in the diagram.
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.left.right.left = new Node(8);
root.left.right.right = new Node(9);
 
u = 4, v = 9;
document.write("The LCA of node " + u +
" and node " + v + " is node "
+ findLCA(root, u, v));
 
// This code is contributed by rag2127
 
</script>


Output

The LCA of node 4 and node 9 is node 2.

Note: 

  1. We assume that the nodes queried are present in the tree.
  2. We also assumed that if there are V nodes in the tree, then the keys (or data) of these nodes are in the range from 1 to V.

Time complexity: 

  1. Euler tour: The number of nodes is V. For a tree, E = V-1. Euler tour (DFS) will take O(V+E) which is O(2*V) which can be written as O(V).
  2. Segment Tree construction : O(n) where n = V + E = 2*V – 1.
  3. Range Minimum query: O(log(n))

Overall this method takes O(n) time for preprocessing but takes O(log n) time for the query. Therefore, it can be useful when we have a single tree on which we want to perform a large number of LCA queries (Note that LCA is useful for finding the shortest path between two nodes of a Binary Tree)

Auxiliary Space:  

  1. Euler tour array: O(n) where n = 2*V – 1
  2. Node Levels array: O(n)
  3. First Occurrences array: O(V)
  4. Segment Tree: O(n)

Overall: O(n)
Another observation is that the adjacent elements in the level array differ by 1. This can be used to convert an RMQ problem to an LCA problem.



Similar Reads

Lowest Common Ancestor in a Binary Tree | Set 3 (Using RMQ)
Given a rooted tree, and two nodes are in the tree, find the Lowest common ancestor of both the nodes. The LCA for two nodes u and v is defined as the farthest node from the root that is the ancestor to both u and v. Prerequisites: LCA | SET 1 Example for the above figure : Input : 4 5 Output : 2 Input : 4 7 Output : 1 Converting LCA to RMQ(Range M
15+ min read
Find LCA for K queries in Complete Binary Tree
Given an integer n. There is a complete binary tree with 2n - 1 nodes. The root of that tree is the node with the value 1, and every node with a value x has two children where the left node has the value 2*x and the right node has the value 2*x + 1, you are given K queries of type (ai, bi), and the task is to return the LCA for the node pair ai and
6 min read
LCA in a tree using Binary Lifting Technique
Given a binary tree, the task is to find the Lowest Common Ancestor of the given two nodes in the tree. Let G be a tree then the LCA of two nodes u and v is defined as the node w in the tree which is an ancestor of both u and v and is farthest from the root node. If one node is the ancestor of another one then that particular node is the LCA of tho
14 min read
Query to find the maximum and minimum weight between two nodes in the given tree using LCA.
Given a tree, and the weights of all the node. Each query contains two integers u and v, the task is to find the minimum and maximum weight on the simple path between u and v (both inclusive). Examples: Input: Query=[{1, 3}, {2, 4}, {3, 5}] Output: -1 5 3 5 -2 5 Explanation: Weight on path 1 to 3 is [-1, 5, -1]. Hence, the minimum and maximum weigh
15+ min read
Longest Common Extension / LCE using RMQ
Prerequisites :  Suffix Array | Set 2kasai's algorithmThe Longest Common Extension (LCE) problem considers a string s and computes, for each pair (L , R), the longest sub string of s that starts at both L and R. In LCE, in each of the query we have to answer the length of the longest common prefix starting at indexes L and R. Example:  String : “ab
15+ min read
Range Minimum Query (RMQ) in Python
Range Minimum Query (RMQ) problem involves finding the minimum value within a specified range of a given array. This problem is used in various fields such as computer science, data structures, and algorithms, with various applications. Examples: Input: arr = [5, 2, 7, 1, 9, 4, 3], Q = [1, 4]Output: 1Explanation: The minimum value within the range
3 min read
Sqrt (or Square Root) Decomposition | Set 2 (LCA of Tree in O(sqrt(height)) time)
Prerequisite: Introduction and DFSThe task is to find LCA of two given nodes in a tree (not necessarily a Binary Tree). In previous posts, we have seen how to calculate LCA using the Sparse Matrix DP approach. In this post, we will see an optimization done on the Naive method by sqrt decomposition technique that works well over the Naive Approach.
15+ min read
LCA for n-ary Tree | Constant Query O(1)
We have seen various methods with different Time Complexities to calculate LCA in n-ary tree:- Method 1 : Naive Method ( by calculating root to node path) | O(n) per query Method 2 :Using Sqrt Decomposition | O(sqrt H) Method 3 : Using Sparse Matrix DP approach | O(logn) Lets study another method that has faster query time than all the above method
15+ min read
Maximize sum of paths from LCA of nodes u and v to one of those nodes
Given a tree consisting of N nodes an array edges[][3] of size N - 1 such that for each {X, Y, W} in edges[] there exists an edge between node X and node Y with a weight of W and two nodes u and v, the task is to find the maximum sum of weights of edges in the path from Lowest Common Ancestor(LCA) of nodes (u, v) to node u and node v. Examples: Inp
14 min read
LCA for general or n-ary trees (Sparse Matrix DP approach )
In previous posts, we have discussed how to calculate the Lowest Common Ancestor (LCA) for a binary tree and a binary search tree (this, this and this). Now let’s look at a method that can calculate LCA for any tree (not only for binary tree). We use Dynamic Programming with Sparse Matrix Approach in our method. This method is very handy and fast w
15+ min read