Given two N-ary trees having M nodes each. Also, given their edges and their roots respectively. The task is to check if they are isomorphic trees or not. If both the trees are isomorphic then print “Yes” else print “No”.
Examples:
Input: M = 9, Root Node of tree-1: 1, Root Node of tree-2: 3
Edges of Tree-1: { (1, 3), (3, 4), (3, 5), (1, 8), (8, 9), (1, 2), (2, 6), (2, 7) }
Edges of Tree-2: { (3, 1), (1, 2), (1, 5), (3, 6), (6, 7), (3, 4), (4, 8), (4, 9) }
Output: YES
Input: M = 9, Root Node of tree-1: 6, Root Node of tree-2: 7
Edges of Tree-1: {(1, 3),(1, 2), (1, 8), (3, 4), (3, 5), (8, 9), (2, 6), (2, 7)}
Edges of Tree-2: {(1, 2), (1, 5), (3, 1), (3, 4), (4, 8), (4, 9), (6, 3), (7, 6)}
Output: NO
Approach:
The idea is to find out the canonical form of both the trees and comparing them. The leaf node will return “()” to its subsequent upper levels.
Below is the example showing the process of finding the canonical form.
Below is the implementation of the above approach:
CPP
// C++ program for the above approach #include <bits/stdc++.h> using namespace std; // To create N-ary tree map< int , vector< int > > tree; // Function which will accept the root // of the tree and its parent (which // is initially "-1") and will return // the canonical form of the tree string ConvertCanonical( int vertex, int parent) { // In this string vector we will // store canonical form of out // current node and its subtree vector<string> child; // Loop to the neighbours of // current vertex for ( auto neighbour : tree[vertex]) { // This is to prevent us from // visiting the parent again if (neighbour == parent) continue ; // DFS call neighbour of our // current vertex & it will // pushback the subtree-structure // of this neighbour into our // child vector. child.push_back(ConvertCanonical( neighbour, vertex)); } // These opening and closing // brackets are for the // current node string str = "(" ; // Sorting function will re-order // the structure of subtree of // the current vertex in a // shortest-subtree-first manner. // Hence we can // now compare the two tree // structures effectively sort(child.begin(), child.end()); for ( auto j : child) str += j; // Append the subtree structure // and enclose it with "(" <subtree> // ")" the opening and closing // brackets of current vertex str += ")" ; // return the subtree-structure // of our Current vertex return str; } // Function to add edges void addedge( int a, int b) { tree[a].push_back(b); tree[b].push_back(a); } // Driver code int main() { // Given N-ary Tree 1 addedge(1, 3); addedge(1, 2); addedge(1, 5); addedge(3, 4); addedge(4, 8); addedge(4, 9); addedge(3, 6); addedge(6, 7); // Function Call to convert Tree 1 // into canonical with 3 is the root // and the parent of root be "-1" string tree1 = ConvertCanonical(3, -1); // Clearing our current tree // before taking input of // next tree tree.clear(); // Given N-ary Tree 2 addedge(1, 3); addedge(3, 4); addedge(3, 5); addedge(1, 8); addedge(8, 9); addedge(1, 2); addedge(2, 6); addedge(2, 7); // Function Call to convert Tree 2 // into canonical string tree2 = ConvertCanonical(1, -1); // Check if canonical form of both // tree are equal or not if (tree1 == tree2) cout << "YES" << endl; else cout << "NO" << endl; return 0; } |
Java
// Java program for the above approach import java.io.*; import java.util.*; class GFG { // To create N-ary tree static Map<Integer, List<Integer> > tree = new HashMap<>(); // Function which will accept the root // of the tree and its parent (which // is initially "-1") and will return // the canonical form of the tree static String ConvertCanonical( int vertex, int parent) { // In this string vector we will // store canonical form of out // current node and its subtree List<String> child = new ArrayList<>(); // Loop to the neighbours of // current vertex for ( int neighbour : tree.getOrDefault(vertex, new ArrayList<>())) { // This is to prevent us from // visiting the parent again if (neighbour == parent) { continue ; } // DFS call neighbour of our // current vertex & it will // pushback the subtree-structure // of this neighbour into our // child vector. child.add(ConvertCanonical(neighbour, vertex)); } // These opening and closing // brackets are for the // current node String str = "(" ; // Sorting function will re-order // the structure of subtree of // the current vertex in a // shortest-subtree-first manner. // Hence we can // now compare the two tree // structures effectively Collections.sort(child); for (String j : child) { str += j; } // Append the subtree structure // and enclose it with "(" <subtree> // ")" the opening and closing // brackets of current vertex str += ")" ; // return the subtree-structure // of our Current vertex return str; } // Function to add edges static void addEdge( int a, int b) { if (!tree.containsKey(a)) { tree.put(a, new ArrayList<>()); } tree.get(a).add(b); if (!tree.containsKey(b)) { tree.put(b, new ArrayList<>()); } tree.get(b).add(a); } public static void main(String[] args) { // Given N-ary Tree 1 addEdge( 1 , 3 ); addEdge( 1 , 2 ); addEdge( 1 , 5 ); addEdge( 3 , 4 ); addEdge( 4 , 8 ); addEdge( 4 , 9 ); addEdge( 3 , 6 ); addEdge( 6 , 7 ); // Function Call to convert Tree 1 // into canonical with 3 is the root // and the parent of root be "-1" String tree1 = ConvertCanonical( 3 , - 1 ); // Clearing our current tree // before taking input of // next tree tree.clear(); // Given N-ary Tree 2 addEdge( 1 , 3 ); addEdge( 3 , 4 ); addEdge( 3 , 5 ); addEdge( 1 , 8 ); addEdge( 8 , 9 ); addEdge( 1 , 2 ); addEdge( 2 , 6 ); addEdge( 2 , 7 ); // Function Call to convert Tree 2 // into canonical String tree2 = ConvertCanonical( 1 , - 1 ); // Check if canonical form of both // tree are equal or not if (tree1.equals(tree2)) { System.out.println( "YES" ); } else { System.out.println( "NO" ); } } } // This code is contributed by karthik. |
Python3
# Python3 program for the above approach # To create N-ary tree tree = dict () # Function which will accept the root # of the tree and its parent (which # is initially "-1") and will return # the canonical form of the tree def ConvertCanonical(vertex, parent): # In this string vector we will # store canonical form of out # current node and its subtree child = [] # Loop to the neighbours of # current vertex for neighbour in tree[vertex] : # This is to prevent us from # visiting the parent again if (neighbour = = parent): continue # DFS call neighbour of our # current vertex & it will # pushback the subtree-structure # of this neighbour into our # child vector. child.append(ConvertCanonical( neighbour, vertex)) # These opening and closing # brackets are for the # current node s = "(" # Sorting function will re-order # the structure of subtree of # the current vertex in a # shortest-subtree-first manner. # Hence we can # now compare the two tree # structures effectively child.sort() for j in child: s + = j # Append the subtree structure # and enclose it with "(" <subtree> # ")" the opening and closing # brackets of current vertex s + = ")" # return the subtree-structure # of our Current vertex return s # Function to add edges def addedge(a, b): if a in tree: tree[a].append(b) else : tree[a] = [b,] if b in tree: tree[b].append(a) else : tree[b] = [a,] # Driver code if __name__ = = '__main__' : # Given N-ary Tree 1 addedge( 1 , 3 ) addedge( 1 , 2 ) addedge( 1 , 5 ) addedge( 3 , 4 ) addedge( 4 , 8 ) addedge( 4 , 9 ) addedge( 3 , 6 ) addedge( 6 , 7 ) # Function Call to convert Tree 1 # into canonical with 3 is the root # and the parent of root be "-1" tree1 = ConvertCanonical( 3 , - 1 ) # Clearing our current tree # before taking input of # next tree tree.clear() # Given N-ary Tree 2 addedge( 1 , 3 ) addedge( 3 , 4 ) addedge( 3 , 5 ) addedge( 1 , 8 ) addedge( 8 , 9 ) addedge( 1 , 2 ) addedge( 2 , 6 ) addedge( 2 , 7 ) # Function Call to convert Tree 2 # into canonical tree2 = ConvertCanonical( 1 , - 1 ) # Check if canonical form of both # tree are equal or not if (tree1 = = tree2): print ( "YES" ) else : print ( "NO" ) |
C#
// C# program for the above approach using System; using System.Collections.Generic; public class GFG { // To create N-ary tree static Dictionary< int , List< int > > tree = new Dictionary< int , List< int > >(); // Function which will accept the root // of the tree and its parent (which // is initially "-1") and will return // the canonical form of the tree static string ConvertCanonical( int vertex, int parent) { // In this string vector we will // store canonical form of out // current node and its subtree List< string > child = new List< string >(); // Loop to the neighbours of // current vertex if (tree.ContainsKey(vertex)) { foreach ( int neighbour in tree[vertex]) { // This is to prevent us from // visiting the parent again if (neighbour == parent) { continue ; } // DFS call neighbour of our // current vertex & it will // pushback the subtree-structure // of this neighbour into our // child vector. child.Add( ConvertCanonical(neighbour, vertex)); } } // These opening and closing // brackets are for the // current node string str = "(" ; // Sorting function will re-order // the structure of subtree of // the current vertex in a // shortest-subtree-first manner. // Hence we can // now compare the two tree // structures effectively child.Sort(); foreach ( string j in child) { str += j; } // Append the subtree structure // and enclose it with "(" <subtree> // ")" the opening and closing // brackets of current vertex str += ")" ; // return the subtree-structure // of our Current vertex return str; } // Function to add edges static void addEdge( int a, int b) { if (!tree.ContainsKey(a)) { tree.Add(a, new List< int >()); } tree[a].Add(b); if (!tree.ContainsKey(b)) { tree.Add(b, new List< int >()); } tree[b].Add(a); } static public void Main() { // Code // Given N-ary Tree 1 addEdge(1, 3); addEdge(1, 2); addEdge(1, 5); addEdge(3, 4); addEdge(4, 8); addEdge(4, 9); addEdge(3, 6); addEdge(6, 7); // Function Call to convert Tree 1 // into canonical with 3 is the root // and the parent of root be "-1" string tree1 = ConvertCanonical(3, -1); // Clearing our current tree // before taking input of // next tree tree.Clear(); // Given N-ary Tree 2 addEdge(1, 3); addEdge(3, 4); addEdge(3, 5); addEdge(1, 8); addEdge(8, 9); addEdge(1, 2); addEdge(2, 6); addEdge(2, 7); // Function Call to convert Tree 2 // into canonical String tree2 = ConvertCanonical(1, -1); // Check if canonical form of both // tree are equal or not if (tree1.Equals(tree2)) { Console.WriteLine( "YES" ); } else { Console.WriteLine( "NO" ); } } } // This code is contributed by lokesh. |
Javascript
<script> // JavaScript code for the above approach // Function to add edges function addedge(a, b) { if (!tree[a]) tree[a] = [] if (!tree[b]) tree[b] = [] tree[a].push(b); tree[b].push(a); } // Function which will accept the root // of the tree and its parent (which // is initially "-1") and will return // the canonical form of the tree function ConvertCanonical(vertex, parent) { // In this string vector we will // store canonical form of out // current node and its subtree let child = []; // Loop to the neighbours of // current vertex for (let neighbour of tree[vertex]) { // This is to prevent us from // visiting the parent again if (neighbour === parent) continue ; // DFS call neighbour of our // current vertex & it will // pushback the subtree-structure // of this neighbour into our // child vector. child.push(ConvertCanonical(neighbour, vertex)); } // These opening and closing // brackets are for the // current node let str = "(" ; // Sorting function will re-order // the structure of subtree of // the current vertex in a // shortest-subtree-first manner. // Hence we can // now compare the two tree // structures effectively child.sort(); for (let j of child) str += j; // Append the subtree structure // and enclose it with "(" <subtree> // ")" the opening and closing // brackets of current vertex str += ")" ; // return the subtree-structure // of our Current vertex return str; } // To create N-ary tree let tree = {}; // Given N-ary Tree 1 addedge(1, 3); addedge(1, 2); addedge(1, 5); addedge(3, 4); addedge(4, 8); addedge(4, 9); addedge(3, 6); addedge(6, 7); // Function Call to convert Tree 1 // into canonical with 3 is the root // and the parent of root be "-1" let tree1 = ConvertCanonical(3, -1); // Clearing our current tree // before taking input of // next tree tree = {}; // Given N-ary Tree 2 addedge(1, 3); addedge(3, 4); addedge(3, 5); addedge(1, 8); addedge(8, 9); addedge(1, 2); addedge(2, 6); addedge(2, 7); // Function Call to convert Tree 2 // into canonical let tree2 = ConvertCanonical(1, -1); // Check if canonical form of both // tree are equal or not if (tree1 === tree2) { console.log( "YES" ); } else { console.log( "NO" ); } // This code is contributed by Potta Lokesh. |
YES
Time complexity: O(N log N), where N is the number of vertices in the tree. This is because for each vertex, we perform a sorting operation on its child vector, which takes O(log N) time in the worst case. Since there are N vertices in the tree, the overall time complexity is O(N log N).
Auxiliary space: O(N), where N is the number of vertices in the tree. This is because we use a map to represent the tree, which takes O(N) space to store all the vertices and their corresponding neighbors. Additionally, during the recursive calls of the ConvertCanonical function, we create a vector of strings to store the canonical form of each vertex and its subtree, which can take up to O(N) space in the worst case.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!