Given a binary tree, determine whether the tree contains any duplicate subtree of size two or more. Two subtrees are considered duplicates if they have the same structure and identical node values. Return true if such a duplicate subtree exists; otherwise, return false.
Note: Subtrees consisting of only a single leaf node are not considered duplicate subtrees.
Example:
Input: root = [1, 2, 3, 4, 5, N, 2, N, N, N, N, 4, 5]
Output: True Explanation: The duplicate subtree is shown below.
Input: root = [1, 2, 3]
Output: False Explanation: There is no duplicate sub-tree in the given binary tree.
[Naive Approach] Generating All Subtrees - O(n ^ 2) Time and O(n ^ 2) Space
The idea is to generate all subtrees (of size greater than 1)of the binary tree and store their Serialized Form in an arrayor hash map. Then iterate through the array/map to check for duplicate subtrees.
Traverse the binary tree recursively in postorder fashion.
Serialize every subtree into a unique string representation.
For null nodes return "N" and for leaf nodes return their value.
Combine current node, left subtree, and right subtree strings to form the serialized subtree.
Store the frequency of every serialized subtree in a hash map.
After traversal, if any subtree frequency is greater than 1, return true; otherwise return false.
C++
#include<bits/stdc++.h>usingnamespacestd;classNode{public:intdata;Node*left,*right;Node(intx){data=x;left=nullptr;right=nullptr;}};// Function which generates all the subtrees// and stores their serialized form in mapstringdupSubRecur(Node*root,unordered_map<string,int>&map){// Base Case:// For null nodesif(root==nullptr){return"N";}// Base Case:// For leaf nodes,// return node value as stringif(root->left==nullptr&&root->right==nullptr){returnto_string(root->data);}// Process left subtreestringleft=dupSubRecur(root->left,map);// Process right subtreestringright=dupSubRecur(root->right,map);// Generate serialized subtreestringcurr="";curr+=to_string(root->data);curr+='*';curr+=left;curr+='*';curr+=right;// Store subtree frequencymap[curr]++;returncurr;}booldupSub(Node*root){unordered_map<string,int>map;// Generate all subtree serializationsdupSubRecur(root,map);// Check duplicate subtreefor(autop:map){// If subtree occurs more than onceif(p.second>1){returntrue;}}returnfalse;}intmain(){// 1// / \ // 2 3// / \ \ // 4 5 2// / \ // 4 5Node*root=newNode(1);root->left=newNode(2);root->right=newNode(3);root->left->left=newNode(4);root->left->right=newNode(5);root->right->right=newNode(2);root->right->right->left=newNode(4);root->right->right->right=newNode(5);// Function Callif(dupSub(root)==true){cout<<"True"<<endl;}else{cout<<"False"<<endl;}return0;}
Java
importjava.util.HashMap;classNode{intdata;Nodeleft,right;Node(intx){data=x;left=null;right=null;}}publicclassGFG{// Function which generates all the subtrees// and stores their serialized form in mapstaticStringdupSubRecur(Noderoot,HashMap<String,Integer>map){// Base Case:// For null nodesif(root==null){return"N";}// Base Case:// For leaf nodes,// return node value as stringif(root.left==null&&root.right==null){returnInteger.toString(root.data);}// Process left subtreeStringleft=dupSubRecur(root.left,map);// Process right subtreeStringright=dupSubRecur(root.right,map);// Generate serialized subtreeStringcurr="";curr+=Integer.toString(root.data);curr+='*';curr+=left;curr+='*';curr+=right;// Store subtree frequencymap.put(curr,map.getOrDefault(curr,0)+1);returncurr;}staticbooleandupSub(Noderoot){HashMap<String,Integer>map=newHashMap<>();// Generate all subtree serializationsdupSubRecur(root,map);// Check duplicate subtreefor(Stringkey:map.keySet()){// If subtree occurs more than onceif(map.get(key)>1){returntrue;}}returnfalse;}publicstaticvoidmain(String[]args){// 1// / \// 2 3// / \ \// 4 5 2// / \// 4 5Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.right=newNode(2);root.right.right.left=newNode(4);root.right.right.right=newNode(5);// Function Callif(dupSub(root)==true){System.out.println("True");}else{System.out.println("False");}}}
Python
classNode:def__init__(self,x):self.data=xself.left=Noneself.right=None# Function which generates all the subtrees# and stores their serialized form in mapdefdupSubRecur(root,mp):# Base Case:# For null nodesifrootisNone:return"N"# Base Case:# For leaf nodes,# return node value as stringifroot.leftisNoneandroot.rightisNone:returnstr(root.data)# Process left subtreeleft=dupSubRecur(root.left,mp)# Process right subtreeright=dupSubRecur(root.right,mp)# Generate serialized subtreecurr=""curr+=str(root.data)curr+='*'curr+=leftcurr+='*'curr+=right# Store subtree frequencymp[curr]=mp.get(curr,0)+1returncurrdefdupSub(root):mp={}# Generate all subtree serializationsdupSubRecur(root,mp)# Check duplicate subtreeforkeyinmp:# If subtree occurs more than onceifmp[key]>1:returnTruereturnFalse# Driver Codeif__name__=="__main__":# 1# / \# 2 3# / \ \# 4 5 2# / \# 4 5root=Node(1)root.left=Node(2)root.right=Node(3)root.left.left=Node(4)root.left.right=Node(5)root.right.right=Node(2)root.right.right.left=Node(4)root.right.right.right=Node(5)# Function CallifdupSub(root)==True:print("True")else:print("False")
C#
usingSystem;usingSystem.Collections.Generic;classNode{publicintdata;publicNodeleft,right;publicNode(intx){data=x;left=null;right=null;}}classGFG{// Function which generates all the subtrees// and stores their serialized form in mapstaticstringDupSubRecur(Noderoot,Dictionary<string,int>map){// Base Case:// For null nodesif(root==null){return"N";}// Base Case:// For leaf nodes,// return node value as stringif(root.left==null&&root.right==null){returnroot.data.ToString();}// Process left subtreestringleft=DupSubRecur(root.left,map);// Process right subtreestringright=DupSubRecur(root.right,map);// Generate serialized subtreestringcurr="";curr+=root.data.ToString();curr+='*';curr+=left;curr+='*';curr+=right;// Store subtree frequencyif(map.ContainsKey(curr)){map[curr]++;}else{map[curr]=1;}returncurr;}staticbooldupSub(Noderoot){Dictionary<string,int>map=newDictionary<string,int>();// Generate all subtree serializationsDupSubRecur(root,map);// Check duplicate subtreeforeach(varpinmap){// If subtree occurs more than onceif(p.Value>1){returntrue;}}returnfalse;}staticvoidMain(){// 1// / \// 2 3// / \ \// 4 5 2// / \// 4 5Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.right=newNode(2);root.right.right.left=newNode(4);root.right.right.right=newNode(5);// Function Callif(dupSub(root)==true){Console.WriteLine("True");}else{Console.WriteLine("False");}}}
JavaScript
classNode{constructor(x){this.data=x;this.left=null;this.right=null;}}// Function which generates all the subtrees// and stores their serialized form in mapfunctiondupSubRecur(root,map){// Base Case:// For null nodesif(root===null){return"N";}// Base Case:// For leaf nodes,// return node value as stringif(root.left===null&&root.right===null){returnroot.data.toString();}// Process left subtreeletleft=dupSubRecur(root.left,map);// Process right subtreeletright=dupSubRecur(root.right,map);// Generate serialized subtreeletcurr="";curr+=root.data.toString();curr+="*";curr+=left;curr+="*";curr+=right;// Store subtree frequencyif(map.has(curr)){map.set(curr,map.get(curr)+1);}else{map.set(curr,1);}returncurr;}functiondupSub(root){letmap=newMap();// Generate all subtree serializationsdupSubRecur(root,map);// Check duplicate subtreefor(let[key,value]ofmap){// If subtree occurs more than onceif(value>1){returntrue;}}returnfalse;}// Driver Code// 1// / \// 2 3// / \ \// 4 5 2// / \// 4 5letroot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.right=newNode(2);root.right.right.left=newNode(4);root.right.right.right=newNode(5);// Function Callif(dupSub(root)===true){console.log("True");}else{console.log("False");}
Output
True
[Optimized Approach] Early Termination DFS - O(n ^ 2) Time and O(n ^ 2) Space
The idea is to use a hash set to store the subtrees in Serialized String Form. For a given subtree of size greater than 1, if its equivalent serializedstring already exists, then return true. If all subtrees are unique, return false.
Traverse the binary tree using recursion in postorder fashion.
Serialize every subtree into a unique string representation.
For null nodes, return "N" and for leaf nodes return their value.
Combine current node, left subtree, and right subtree strings to form the serialization.
Check whether the serialized subtree already exists in the hash set.
If it already exists, return true; otherwise store it in the set and continue traversal.
C++
#include<bits/stdc++.h>usingnamespacestd;classNode{public:intdata;Node*left,*right;Node(intx){data=x;left=nullptr;right=nullptr;}};// Function to serialize subtreestringdupSubRecur(Node*root,unordered_set<string>&s){// Base Case:// For null nodesif(root==nullptr){return"N";}// Base Case:// For leaf nodesif(root->left==nullptr&&root->right==nullptr){returnto_string(root->data);}// Process left subtreestringleft=dupSubRecur(root->left,s);// If duplicate already found,// stop further recursionif(left=="#"){return"#";}// Process right subtreestringright=dupSubRecur(root->right,s);// If duplicate already found,// stop further recursionif(right=="#"){return"#";}// Create serialization stringstringcurr="";curr+=to_string(root->data);curr+='*';curr+=left;curr+='*';curr+=right;// If subtree already exists,// duplicate subtree foundif(s.find(curr)!=s.end()){return"#";}// Store subtree serializations.insert(curr);returncurr;}booldupSub(Node*root){unordered_set<string>s;// If duplicate found,// function returns "#"return(dupSubRecur(root,s)=="#");}intmain(){// 1// / \ // 2 3// / \ \ // 4 5 2// / \ // 4 5Node*root=newNode(1);root->left=newNode(2);root->right=newNode(3);root->left->left=newNode(4);root->left->right=newNode(5);root->right->right=newNode(2);root->right->right->left=newNode(4);root->right->right->right=newNode(5);// Function Callif(dupSub(root)==true){cout<<"True"<<endl;}else{cout<<"False"<<endl;}return0;}
Java
importjava.util.HashSet;classNode{intdata;Nodeleft,right;Node(intx){data=x;left=null;right=null;}}publicclassGFG{// Function to serialize subtreestaticStringdupSubRecur(Noderoot,HashSet<String>set){// Base Case:// For null nodesif(root==null){return"N";}// Base Case:// For leaf nodesif(root.left==null&&root.right==null){returnInteger.toString(root.data);}// Process left subtreeStringleft=dupSubRecur(root.left,set);// If duplicate already found,// stop further recursionif(left.equals("#")){return"#";}// Process right subtreeStringright=dupSubRecur(root.right,set);// If duplicate already found,// stop further recursionif(right.equals("#")){return"#";}// Create serialization stringStringcurr="";curr+=Integer.toString(root.data);curr+='*';curr+=left;curr+='*';curr+=right;// If subtree already exists,// duplicate subtree foundif(set.contains(curr)){return"#";}// Store subtree serializationset.add(curr);returncurr;}staticbooleandupSub(Noderoot){HashSet<String>set=newHashSet<>();// If duplicate found,// function returns "#"returndupSubRecur(root,set).equals("#");}publicstaticvoidmain(String[]args){// 1// / \// 2 3// / \ \// 4 5 2// / \// 4 5Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.right=newNode(2);root.right.right.left=newNode(4);root.right.right.right=newNode(5);// Function Callif(dupSub(root)==true){System.out.println("True");}else{System.out.println("False");}}}
Python
classNode:def__init__(self,x):self.data=xself.left=Noneself.right=None# Function to serialize subtreedefdupSubRecur(root,s):# Base Case:# For null nodesifrootisNone:return"N"# Base Case:# For leaf nodesifroot.leftisNoneandroot.rightisNone:returnstr(root.data)# Process left subtreeleft=dupSubRecur(root.left,s)# If duplicate already found,# stop further recursionifleft=="#":return"#"# Process right subtreeright=dupSubRecur(root.right,s)# If duplicate already found,# stop further recursionifright=="#":return"#"# Create serialization stringcurr=""curr+=str(root.data)curr+='*'curr+=leftcurr+='*'curr+=right# If subtree already exists,# duplicate subtree foundifcurrins:return"#"# Store subtree serializations.add(curr)returncurrdefdupSub(root):s=set()# If duplicate found,# function returns "#"returndupSubRecur(root,s)=="#"# Driver Codeif__name__=="__main__":# 1# / \# 2 3# / \ \# 4 5 2# / \# 4 5root=Node(1)root.left=Node(2)root.right=Node(3)root.left.left=Node(4)root.left.right=Node(5)root.right.right=Node(2)root.right.right.left=Node(4)root.right.right.right=Node(5)# Function CallifdupSub(root)==True:print("True")else:print("False")
C#
usingSystem;usingSystem.Collections.Generic;classNode{publicintdata;publicNodeleft,right;publicNode(intx){data=x;left=null;right=null;}}classGFG{// Function to serialize subtreestaticstringDupSubRecur(Noderoot,HashSet<string>set){// Base Case:// For null nodesif(root==null){return"N";}// Base Case:// For leaf nodesif(root.left==null&&root.right==null){returnroot.data.ToString();}// Process left subtreestringleft=DupSubRecur(root.left,set);// If duplicate already found,// stop further recursionif(left=="#"){return"#";}// Process right subtreestringright=DupSubRecur(root.right,set);// If duplicate already found,// stop further recursionif(right=="#"){return"#";}// Create serialization stringstringcurr="";curr+=root.data.ToString();curr+='*';curr+=left;curr+='*';curr+=right;// If subtree already exists,// duplicate subtree foundif(set.Contains(curr)){return"#";}// Store subtree serializationset.Add(curr);returncurr;}staticbooldupSub(Noderoot){HashSet<string>set=newHashSet<string>();// If duplicate found,// function returns "#"returnDupSubRecur(root,set)=="#";}staticvoidMain(){// 1// / \// 2 3// / \ \// 4 5 2// / \// 4 5Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.right=newNode(2);root.right.right.left=newNode(4);root.right.right.right=newNode(5);// Function Callif(dupSub(root)==true){Console.WriteLine("True");}else{Console.WriteLine("False");}}}
JavaScript
classNode{constructor(x){this.data=x;this.left=null;this.right=null;}}// Function to serialize subtreefunctiondupSubRecur(root,set){// Base Case:// For null nodesif(root===null){return"N";}// Base Case:// For leaf nodesif(root.left===null&&root.right===null){returnroot.data.toString();}// Process left subtreeletleft=dupSubRecur(root.left,set);// If duplicate already found,// stop further recursionif(left==="#"){return"#";}// Process right subtreeletright=dupSubRecur(root.right,set);// If duplicate already found,// stop further recursionif(right==="#"){return"#";}// Create serialization stringletcurr="";curr+=root.data.toString();curr+="*";curr+=left;curr+="*";curr+=right;// If subtree already exists,// duplicate subtree foundif(set.has(curr)){return"#";}// Store subtree serializationset.add(curr);returncurr;}functiondupSub(root){letset=newSet();// If duplicate found,// function returns "#"returndupSubRecur(root,set)==="#";}// Driver Code// 1// / \// 2 3// / \ \// 4 5 2// / \// 4 5letroot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.right=newNode(2);root.right.right.left=newNode(4);root.right.right.right=newNode(5);// Function Callif(dupSub(root)===true){console.log("True");}else{console.log("False");}