Given two Binary Trees, the task is to check whether they are isomorphic or not. Two trees are called isomorphic if one of them can be obtained from the other by a series of flips, i.e. by swapping left and right children of several nodes. Any number of nodes at any level can have their children swapped.
Note:
- If two trees are the same (same structure and node values), they are isomorphic.
- Two empty trees are isomorphic.
- If the root node values of both trees differ, they are not isomorphic.
Examples:
Input:
Output: True
Explanation: The above two trees are isomorphic with following sub-trees flipped: 2 and 3, NULL and 6, 7 and 8.
[Expected Approach - 1] Using Recursion - O(n) Time and O(n) Space
The idea is to traverse both trees recursively, comparing the nodes n1 and n2. Their data must be the same, and their subtrees must either be identical or mirror images (flipped). This ensures that the trees are structurally isomorphic.
Follow the steps to solve the problem:
Let the current internal nodes of the two trees be n1 and n2. For the subtrees rooted at n1 and n2 to be isomorphic, the following conditions must hold:
- The data of n1 and n2 must be the same.
- One of the following two conditions must be true for the children of n1 and n2:
- The left child of n1 is isomorphic to the left child of n2, and the right child of n1 is isomorphic to the right child of n2.
- The left child of n1 is isomorphic to the right child of n2, and the right child of n1 is isomorphic to the left child of n2.
- This ensures that the trees are either structurally identical or have been "flipped" at some levels while still being isomorphic.
Below is the implementation of the above approach:
C++ // C++ code to check if two trees are // isomorphic using recursion #include <bits/stdc++.h> using namespace std; class Node { public: int data; Node *left, *right; Node(int x) { data = x; left = right = nullptr; } }; // Function to check if two trees are isomorphic bool isIsomorphic(Node* root1, Node* root2) { // Both roots are NULL, trees are isomorphic // by definition if (root1 == nullptr && root2 == nullptr) { return true; } // Exactly one of the root1 and root2 is NULL, // trees not isomorphic if (root1 == nullptr || root2 == nullptr) { return false; } // If the data doesn't match, trees // are not isomorphic if (root1->data != root2->data) { return false; } // Check if the trees are isomorphic by // considering the two cases: // Case 1: The subtrees have not been flipped // Case 2: The subtrees have been flipped return (isIsomorphic(root1->left, root2->left) && isIsomorphic(root1->right, root2->right)) || (isIsomorphic(root1->left, root2->right) && isIsomorphic(root1->right, root2->left)); } int main() { // Representation of input binary tree 1 // 1 // / \ // 2 3 // / \ // 4 5 // / \ // 7 8 Node* root1 = new Node(1); root1->left = new Node(2); root1->right = new Node(3); root1->left->left = new Node(4); root1->left->right = new Node(5); root1->left->right->left = new Node(7); root1->left->right->right = new Node(8); // Representation of input binary tree 2 // 1 // / \ // 3 2 // / / \ // 6 4 5 // / \ // 8 7 Node* root2 = new Node(1); root2->left = new Node(3); root2->right = new Node(2); root2->left->left = new Node(6); root2->right->left = new Node(4); root2->right->right = new Node(5); root2->right->right->left = new Node(8); root2->right->right->right = new Node(7); if (isIsomorphic(root1, root2)) { cout << "True\n"; } else { cout << "False\n"; } return 0; }
Java // Java code to check if two trees are // isomorphic using recursion import java.util.*; class Node { int data; Node left, right; Node(int x) { data = x; left = right = null; } } class GfG { // Function to check if two trees are isomorphic static boolean isIsomorphic(Node root1, Node root2) { // Both roots are NULL, trees are // isomorphic by definition if (root1 == null && root2 == null) { return true; } // Exactly one of the root1 and root2 is NULL, // trees not isomorphic if (root1 == null || root2 == null) { return false; } // If the data doesn't match, trees are not isomorphic if (root1.data != root2.data) { return false; } // Check if the trees are isomorphic by // considering the two cases: // Case 1: The subtrees have not been flipped // Case 2: The subtrees have been flipped return (isIsomorphic(root1.left, root2.left) && isIsomorphic(root1.right, root2.right)) || (isIsomorphic(root1.left, root2.right) && isIsomorphic(root1.right, root2.left)); } public static void main(String[] args) { // Representation of input binary tree 1 // 1 // / \ // 2 3 // / \ // 4 5 // / \ // 7 8 Node root1 = new Node(1); root1.left = new Node(2); root1.right = new Node(3); root1.left.left = new Node(4); root1.left.right = new Node(5); root1.left.right.left = new Node(7); root1.left.right.right = new Node(8); // Representation of input binary tree 2 // 1 // / \ // 3 2 // / / \ // 6 4 5 // / \ // 8 7 Node root2 = new Node(1); root2.left = new Node(3); root2.right = new Node(2); root2.left.left = new Node(6); root2.right.left = new Node(4); root2.right.right = new Node(5); root2.right.right.left = new Node(8); root2.right.right.right = new Node(7); if (isIsomorphic(root1, root2)) { System.out.println("True"); } else { System.out.println("False"); } } }
Python # Python code to check if two trees are # isomorphic using recursion class Node: def __init__(self, x): self.data = x self.left = None self.right = None # Function to check if two trees are isomorphic def isIsomorphic(root1, root2): # Both roots are None, trees are # isomorphic by definition if root1 is None and root2 is None: return True # Exactly one of the root1 and root2 is None, # trees not isomorphic if root1 is None or root2 is None: return False # If the data doesn't match, trees are not isomorphic if root1.data != root2.data: return False # Check if the trees are isomorphic by considering # the two cases: # Case 1: The subtrees have not been flipped # Case 2: The subtrees have been flipped return (isIsomorphic(root1.left, root2.left) and isIsomorphic(root1.right, root2.right)) or \ (isIsomorphic(root1.left, root2.right) and isIsomorphic(root1.right, root2.left)) if __name__ == "__main__": # Representation of input binary tree 1 # 1 # / \ # 2 3 # / \ # 4 5 # / \ # 7 8 root1 = Node(1) root1.left = Node(2) root1.right = Node(3) root1.left.left = Node(4) root1.left.right = Node(5) root1.left.right.left = Node(7) root1.left.right.right = Node(8) # Representation of input binary tree 2 # 1 # / \ # 3 2 # / / \ # 6 4 5 # / \ # 8 7 root2 = Node(1) root2.left = Node(3) root2.right = Node(2) root2.left.left = Node(6) root2.right.left = Node(4) root2.right.right = Node(5) root2.right.right.left = Node(8) root2.right.right.right = Node(7) if isIsomorphic(root1, root2): print("True") else: print("False")
C# // C# code to check if two trees are // isomorphic using recursion using System; class Node { public int data; public Node left, right; public Node(int x) { data = x; left = right = null; } } class GfG { // Function to check if two trees are isomorphic static bool isIsomorphic(Node root1, Node root2) { // Both roots are null, trees are // isomorphic by definition if (root1 == null && root2 == null) { return true; } // Exactly one of the root1 and root2 is null, // trees not isomorphic if (root1 == null || root2 == null) { return false; } // If the data doesn't match, trees are not isomorphic if (root1.data != root2.data) { return false; } // Check if the trees are isomorphic by // considering the two cases: // Case 1: The subtrees have not been flipped // Case 2: The subtrees have been flipped return (isIsomorphic(root1.left, root2.left) && isIsomorphic(root1.right, root2.right)) || (isIsomorphic(root1.left, root2.right) && isIsomorphic(root1.right, root2.left)); } static void Main(string[] args) { // Representation of input binary tree 1 // 1 // / \ // 2 3 // / \ // 4 5 // / \ // 7 8 Node root1 = new Node(1); root1.left = new Node(2); root1.right = new Node(3); root1.left.left = new Node(4); root1.left.right = new Node(5); root1.left.right.left = new Node(7); root1.left.right.right = new Node(8); // Representation of input binary tree 2 // 1 // / \ // 3 2 // / / \ // 6 4 5 // / \ // 8 7 Node root2 = new Node(1); root2.left = new Node(3); root2.right = new Node(2); root2.left.left = new Node(6); root2.right.left = new Node(4); root2.right.right = new Node(5); root2.right.right.left = new Node(8); root2.right.right.right = new Node(7); if (isIsomorphic(root1, root2)) { Console.WriteLine("True"); } else { Console.WriteLine("False"); } } }
JavaScript // Javascript code to check if two trees are // isomorphic using recursion class Node { constructor(x) { this.data = x; this.left = null; this.right = null; } } // Function to check if two trees are isomorphic function isIsomorphic(root1, root2) { // Both roots are null, trees are isomorphic // by definition if (root1 === null && root2 === null) { return true; } // Exactly one of the root1 and root2 is null, // trees not isomorphic if (root1 === null || root2 === null) { return false; } // If the data doesn't match, trees are not isomorphic if (root1.data !== root2.data) { return false; } // Check if the trees are isomorphic by // considering the two cases: // Case 1: The subtrees have not been flipped // Case 2: The subtrees have been flipped return (isIsomorphic(root1.left, root2.left) && isIsomorphic(root1.right, root2.right)) || (isIsomorphic(root1.left, root2.right) && isIsomorphic(root1.right, root2.left)); } // Representation of input binary tree 1 // 1 // / \ // 2 3 // / \ // 4 5 // / \ // 7 8 const root1 = new Node(1); root1.left = new Node(2); root1.right = new Node(3); root1.left.left = new Node(4); root1.left.right = new Node(5); root1.left.right.left = new Node(7); root1.left.right.right = new Node(8); // Representation of input binary tree 2 // 1 // / \ // 3 2 // / / \ // 6 4 5 // / \ // 8 7 const root2 = new Node(1); root2.left = new Node(3); root2.right = new Node(2); root2.left.left = new Node(6); root2.right.left = new Node(4); root2.right.right = new Node(5); root2.right.right.left = new Node(8); root2.right.right.right = new Node(7); if (isIsomorphic(root1, root2)) { console.log("True"); } else { console.log("False"); }
Time Complexity: O(n), because each node in both trees is visited once during the isomorphism check, where n is the total number of nodes in the trees.
Auxiliary Space: O(h), due to the recursion stack, where h is the height of the trees; in the worst case, this can be O(n) for skewed trees.
[Expected Approach - 2] Using Iteration - O(n) Time and O(n) Space
To solve the question mentioned above we traverse both the trees iteratively using level order traversal and store the levels in a queue data structure. There are following two conditions at each level
- The value of nodes has to be the same.
- The number of nodes at each level should be the same.
Please refer to Iterative Approach to check if two Binary Trees are Isomorphic or not for implementation.