Lowest Common Ancestor for a Set of Nodes in a Rooted Tree
Given a rooted tree with N nodes, the task is to find the Lowest Common Ancestor for a given set of nodes V of that tree.
Examples:
Input: 1 / | \ 2 3 4 / \ | | 5 6 7 10 / \ 8 9 V[] = {7, 3, 8, 9} Output: 3 Input: 1 / | \ 2 3 4 / \ | | 5 6 7 10 / \ 8 9 V[] = {4, 6, 7} Output: 1
Approach: We can observe that
- the Lowest Common Ancestors for any set of nodes will have in-time less than or equal to that of all nodes in the set and out-time greater than or equal(equal if LCA is present in the set) to that of all nodes in the set.
- Thus, in order to solve the problem, we need to traverse the entire tree starting from the root node using Depth First Search Traversal and store the in-time, out-time, and level for every node.
- The node with in-time less than or equal to all the nodes in the set and out-time greater than or equal to all the nodes in the set and with maximum level possible is the answer.
Below is the implementation of the above approach:
C++
// C++ Program to find the LCA // in a rooted tree for a given // set of nodes #include <bits/stdc++.h> using namespace std; // Set time 1 initially int T = 1; void dfs( int node, int parent, vector< int > g[], int level[], int t_in[], int t_out[]) { // Case for root node if (parent == -1) { level[node] = 1; } else { level[node] = level[parent] + 1; } // In-time for node t_in[node] = T; for ( auto i : g[node]) { if (i != parent) { T++; dfs(i, node, g, level, t_in, t_out); } } T++; // Out-time for the node t_out[node] = T; } int findLCA( int n, vector< int > g[], vector< int > v) { // level[i]--> Level of node i int level[n + 1]; // t_in[i]--> In-time of node i int t_in[n + 1]; // t_out[i]--> Out-time of node i int t_out[n + 1]; // Fill the level, in-time // and out-time of all nodes dfs(1, -1, g, level, t_in, t_out); int mint = INT_MAX, maxt = INT_MIN; int minv = -1, maxv = -1; for ( auto i = v.begin(); i != v.end(); i++) { // To find minimum in-time among // all nodes in LCA set if (t_in[*i] < mint) { mint = t_in[*i]; minv = *i; } // To find maximum in-time among // all nodes in LCA set if (t_out[*i] > maxt) { maxt = t_out[*i]; maxv = *i; } } // Node with same minimum // and maximum out time // is LCA for the set if (minv == maxv) { return minv; } // Take the minimum level as level of LCA int lev = min(level[minv], level[maxv]); int node, l = INT_MIN; for ( int i = 1; i <= n; i++) { // If i-th node is at a higher level // than that of the minimum among // the nodes of the given set if (level[i] > lev) continue ; // Compare in-time, out-time // and level of i-th node // to the respective extremes // among all nodes of the given set if (t_in[i] <= mint && t_out[i] >= maxt && level[i] > l) { node = i; l = level[i]; } } return node; } // Driver code int main() { int n = 10; vector< int > g[n + 1]; g[1].push_back(2); g[2].push_back(1); g[1].push_back(3); g[3].push_back(1); g[1].push_back(4); g[4].push_back(1); g[2].push_back(5); g[5].push_back(2); g[2].push_back(6); g[6].push_back(2); g[3].push_back(7); g[7].push_back(3); g[4].push_back(10); g[10].push_back(4); g[8].push_back(7); g[7].push_back(8); g[9].push_back(7); g[7].push_back(9); vector< int > v = { 7, 3, 8 }; cout << findLCA(n, g, v) << endl; } |
Java
// Java Program to find the LCA // in a rooted tree for a given // set of nodes import java.util.*; class GFG { // Set time 1 initially static int T = 1 ; static void dfs( int node, int parent, Vector<Integer> g[], int level[], int t_in[], int t_out[]) { // Case for root node if (parent == - 1 ) { level[node] = 1 ; } else { level[node] = level[parent] + 1 ; } // In-time for node t_in[node] = T; for ( int i : g[node]) { if (i != parent) { T++; dfs(i, node, g, level, t_in, t_out); } } T++; // Out-time for the node t_out[node] = T; } static int findLCA( int n, Vector<Integer> g[], Vector<Integer> v) { // level[i]-. Level of node i int []level = new int [n + 1 ]; // t_in[i]-. In-time of node i int []t_in = new int [n + 1 ]; // t_out[i]-. Out-time of node i int []t_out = new int [n + 1 ]; // Fill the level, in-time // and out-time of all nodes dfs( 1 , - 1 , g, level, t_in, t_out); int mint = Integer.MAX_VALUE, maxt = Integer.MIN_VALUE; int minv = - 1 , maxv = - 1 ; for ( int i = 0 ; i <v.size(); i++) { // To find minimum in-time among // all nodes in LCA set if (t_in[v.get(i)] < mint) { mint = t_in[v.get(i)]; minv = v.get(i); } // To find maximum in-time among // all nodes in LCA set if (t_out[v.get(i)] > maxt) { maxt = t_out[v.get(i)]; maxv = v.get(i); } } // Node with same minimum // and maximum out time // is LCA for the set if (minv == maxv) { return minv; } // Take the minimum level as level of LCA int lev = Math.min(level[minv], level[maxv]); int node = 0 , l = Integer.MIN_VALUE; for ( int i = 1 ; i <= n; i++) { // If i-th node is at a higher level // than that of the minimum among // the nodes of the given set if (level[i] > lev) continue ; // Compare in-time, out-time // and level of i-th node // to the respective extremes // among all nodes of the given set if (t_in[i] <= mint && t_out[i] >= maxt && level[i] > l) { node = i; l = level[i]; } } return node; } // Driver code public static void main(String[] args) { int n = 10 ; Vector<Integer> []g = new Vector[n + 1 ]; for ( int i = 0 ; i < g.length; i++) g[i] = new Vector<Integer>(); g[ 1 ].add( 2 ); g[ 2 ].add( 1 ); g[ 1 ].add( 3 ); g[ 3 ].add( 1 ); g[ 1 ].add( 4 ); g[ 4 ].add( 1 ); g[ 2 ].add( 5 ); g[ 5 ].add( 2 ); g[ 2 ].add( 6 ); g[ 6 ].add( 2 ); g[ 3 ].add( 7 ); g[ 7 ].add( 3 ); g[ 4 ].add( 10 ); g[ 10 ].add( 4 ); g[ 8 ].add( 7 ); g[ 7 ].add( 8 ); g[ 9 ].add( 7 ); g[ 7 ].add( 9 ); Vector<Integer> v = new Vector<>(); v.add( 7 ); v.add( 3 ); v.add( 8 ); System.out.print(findLCA(n, g, v) + "\n" ); } } // This code is contributed by aashish1995. |
Python3
# Python Program to find the LCA # in a rooted tree for a given # set of nodes from typing import List from sys import maxsize INT_MAX = maxsize INT_MIN = - maxsize # Set time 1 initially T = 1 def dfs(node: int , parent: int , g: List [ List [ int ]], level: List [ int ], t_in: List [ int ], t_out: List [ int ]) - > None : global T # Case for root node if (parent = = - 1 ): level[node] = 1 else : level[node] = level[parent] + 1 # In-time for node t_in[node] = T for i in g[node]: if (i ! = parent): T + = 1 dfs(i, node, g, level, t_in, t_out) T + = 1 # Out-time for the node t_out[node] = T def findLCA(n: int , g: List [ List [ int ]], v: List [ int ]) - > int : # level[i]--> Level of node i level = [ 0 for _ in range (n + 1 )] # t_in[i]--> In-time of node i t_in = [ 0 for _ in range (n + 1 )] # t_out[i]--> Out-time of node i t_out = [ 0 for _ in range (n + 1 )] # Fill the level, in-time # and out-time of all nodes dfs( 1 , - 1 , g, level, t_in, t_out) mint = INT_MAX maxt = INT_MIN minv = - 1 maxv = - 1 for i in v: # To find minimum in-time among # all nodes in LCA set if (t_in[i] < mint): mint = t_in[i] minv = i # To find maximum in-time among # all nodes in LCA set if (t_out[i] > maxt): maxt = t_out[i] maxv = i # Node with same minimum # and maximum out time # is LCA for the set if (minv = = maxv): return minv # Take the minimum level as level of LCA lev = min (level[minv], level[maxv]) node = 0 l = INT_MIN for i in range (n): # If i-th node is at a higher level # than that of the minimum among # the nodes of the given set if (level[i] > lev): continue # Compare in-time, out-time # and level of i-th node # to the respective extremes # among all nodes of the given set if (t_in[i] < = mint and t_out[i] > = maxt and level[i] > l): node = i l = level[i] return node # Driver code if __name__ = = "__main__" : n = 10 g = [[] for _ in range (n + 1 )] g[ 1 ].append( 2 ) g[ 2 ].append( 1 ) g[ 1 ].append( 3 ) g[ 3 ].append( 1 ) g[ 1 ].append( 4 ) g[ 4 ].append( 1 ) g[ 2 ].append( 5 ) g[ 5 ].append( 2 ) g[ 2 ].append( 6 ) g[ 6 ].append( 2 ) g[ 3 ].append( 7 ) g[ 7 ].append( 3 ) g[ 4 ].append( 10 ) g[ 10 ].append( 4 ) g[ 8 ].append( 7 ) g[ 7 ].append( 8 ) g[ 9 ].append( 7 ) g[ 7 ].append( 9 ) v = [ 7 , 3 , 8 ] print (findLCA(n, g, v)) # This code is contributed by sanjeev2552 |
C#
// C# Program to find the LCA // in a rooted tree for a given // set of nodes using System; using System.Collections.Generic; public class GFG { // Set time 1 initially static int T = 1; static void dfs( int node, int parent, List< int > []g, int []level, int []t_in, int []t_out) { // Case for root node if (parent == -1) { level[node] = 1; } else { level[node] = level[parent] + 1; } // In-time for node t_in[node] = T; foreach ( int i in g[node]) { if (i != parent) { T++; dfs(i, node, g, level, t_in, t_out); } } T++; // Out-time for the node t_out[node] = T; } static int findLCA( int n, List< int > []g, List< int > v) { // level[i]-. Level of node i int []level = new int [n + 1]; // t_in[i]-. In-time of node i int []t_in = new int [n + 1]; // t_out[i]-. Out-time of node i int []t_out = new int [n + 1]; // Fill the level, in-time // and out-time of all nodes dfs(1, -1, g, level, t_in, t_out); int mint = int .MaxValue, maxt = int .MinValue; int minv = -1, maxv = -1; for ( int i = 0; i < v.Count; i++) { // To find minimum in-time among // all nodes in LCA set if (t_in[v[i]] < mint) { mint = t_in[v[i]]; minv = v[i]; } // To find maximum in-time among // all nodes in LCA set if (t_out[v[i]] > maxt) { maxt = t_out[v[i]]; maxv = v[i]; } } // Node with same minimum // and maximum out time // is LCA for the set if (minv == maxv) { return minv; } // Take the minimum level as level of LCA int lev = Math.Min(level[minv], level[maxv]); int node = 0, l = int .MinValue; for ( int i = 1; i <= n; i++) { // If i-th node is at a higher level // than that of the minimum among // the nodes of the given set if (level[i] > lev) continue ; // Compare in-time, out-time // and level of i-th node // to the respective extremes // among all nodes of the given set if (t_in[i] <= mint && t_out[i] >= maxt && level[i] > l) { node = i; l = level[i]; } } return node; } // Driver code public static void Main(String[] args) { int n = 10; List< int > []g = new List< int >[n + 1]; for ( int i = 0; i < g.Length; i++) g[i] = new List< int >(); g[1].Add(2); g[2].Add(1); g[1].Add(3); g[3].Add(1); g[1].Add(4); g[4].Add(1); g[2].Add(5); g[5].Add(2); g[2].Add(6); g[6].Add(2); g[3].Add(7); g[7].Add(3); g[4].Add(10); g[10].Add(4); g[8].Add(7); g[7].Add(8); g[9].Add(7); g[7].Add(9); List< int > v = new List< int >(); v.Add(7); v.Add(3); v.Add(8); Console.Write(findLCA(n, g, v) + "\n" ); } } // This code is contributed by Rajput-Ji |
Javascript
<script> // JavaScript Program to find the LCA // in a rooted tree for a given // set of nodes // Set time 1 initially let T = 1; function dfs(node, parent, g, level, t_in, t_out) { // Case for root node if (parent == -1) { level[node] = 1; } else { level[node] = level[parent] + 1; } // In-time for node t_in[node] = T; for (let i = 0; i < g[node].length; i++) { if (g[node][i] != parent) { T++; dfs(g[node][i], node, g, level, t_in, t_out); } } T++; // Out-time for the node t_out[node] = T; } function findLCA(n, g, v) { // level[i]-. Level of node i let level = new Array(n + 1); // t_in[i]-. In-time of node i let t_in = new Array(n + 1); // t_out[i]-. Out-time of node i let t_out = new Array(n + 1); // Fill the level, in-time // and out-time of all nodes dfs(1, -1, g, level, t_in, t_out); let mint = Number.MAX_VALUE, maxt = Number.MIN_VALUE; let minv = -1, maxv = -1; for (let i =0; i < v.length; i++) { // To find minimum in-time among // all nodes in LCA set if (t_in[v[i]] < mint) { mint = t_in[v[i]]; minv = v[i]; } // To find maximum in-time among // all nodes in LCA set if (t_out[v[i]] > maxt) { maxt = t_out[v[i]]; maxv = v[i]; } } // Node with same minimum // and maximum out time // is LCA for the set if (minv == maxv) { return minv; } // Take the minimum level as level of LCA let lev = Math.min(level[minv], level[maxv]); let node = 0, l = Number.MIN_VALUE; for (let i = 1; i <= n; i++) { // If i-th node is at a higher level // than that of the minimum among // the nodes of the given set if (level[i] > lev) continue ; // Compare in-time, out-time // and level of i-th node // to the respective extremes // among all nodes of the given set if (t_in[i] <= mint && t_out[i] >= maxt && level[i] > l) { node = i; l = level[i]; } } return node; } let n = 10; let g = new Array(n + 1); for (let i = 0; i < g.length; i++) g[i] = []; g[1].push(2); g[2].push(1); g[1].push(3); g[3].push(1); g[1].push(4); g[4].push(1); g[2].push(5); g[5].push(2); g[2].push(6); g[6].push(2); g[3].push(7); g[7].push(3); g[4].push(10); g[10].push(4); g[8].push(7); g[7].push(8); g[9].push(7); g[7].push(9); let v = []; v.push(7); v.push(3); v.push(8); document.write(findLCA(n, g, v) + "</br>" ); </script> |
Output:
3
Time Complexity: O(N)
Space Complexity: O(N)
Please Login to comment...