Given the roots of two binary trees, p and q, determine whether the two trees are identical.
Two binary trees are identical only if:
Their structure is exactly the same.
Nodes at corresponding positions contain the same values.
If both trees are empty, they are considered identical. If only one tree is empty, they are not identical.
Example 1
Input: p = [1, 2, 3], q = [1, 2, 3]
Output: true
Explanation: Both trees have the same structure, and every pair of corresponding nodes contains the same value. Therefore, the trees are identical.
Example 2
Input: p = [1, 2], q = [1, null, 2]
Output: false
Explanation: Both trees contain the values 1 and 2, but their structures are different. In p, node 2 is the left child of 1, while in q, node 2 is the right child of 1. Therefore, the trees are not identical.
Approach 1
Two trees are identical only when the nodes at every corresponding position match in both existence and value.
Recursion fits naturally because after comparing the current pair of nodes, the same condition must hold for their left subtrees and their right subtrees.
If both current nodes are null, that position matches. If only one is null, the structure differs. Otherwise, their values must match before checking the corresponding children.
Algorithm
If both
pandqarenull, returntruebecause both subtrees are empty.If exactly one of them is
null, returnfalsebecause their structures differ.Compare
p.valandq.val; returnfalseimmediately if the values are different.Recursively compare
p.leftwithq.leftto verify the left subtrees.Recursively compare
p.rightwithq.rightto verify the right subtrees.Return
trueonly if both recursive comparisons aretrue.
Dry Run
Same Tree Appraoch 1 Dry Run.png
Solution
#include <bits/stdc++.h>using namespace std;struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int value) { val = value; left = nullptr; right = nullptr; }};class Solution {public: // Compares corresponding nodes // of both trees recursively. bool isSameTree(TreeNode* p, TreeNode* q) { // Both trees are empty // at this position. if (p == nullptr && q == nullptr) { return true; } // Only one node exists, // so the structures differ. if (p == nullptr || q == nullptr) { return false; } // Different values make // the trees non-identical. if (p->val != q->val) { return false; } // Both corresponding subtrees // must also be identical. return isSameTree(p->left, q->left) && isSameTree(p->right, q->right); }};int main() { TreeNode* p = new TreeNode(1); p->left = new TreeNode(2); p->right = new TreeNode(3); TreeNode* q = new TreeNode(1); q->left = new TreeNode(2); q->right = new TreeNode(3); Solution solution; cout << ( solution.isSameTree(p, q) ? "true" : "false" ) << endl; return 0;}Complexity Analysis
Time Complexity: O(N), where N is the number of nodes in either tree in the worst case. Every corresponding node position is checked at most once.
Space Complexity: O(H), where H is the maximum height of the two trees, due to the recursion stack. This becomes O(N) for a skewed tree and O(log N) for a balanced tree.
Approach 2
The recursive solution compares corresponding positions in both trees. The same comparison can be performed iteratively by storing pairs of corresponding nodes in a queue.
For every pair, first verify that their structure matches and then compare their values. If the pair is valid, their left children are paired together and their right children are paired together.
Any mismatch can return false immediately.
Algorithm
Push the initial pair
(p, q)into a queue because comparison begins at the roots.Remove one pair at a time from the queue.
If both nodes are
null, continue because that position matches; if exactly one isnull, returnfalse.If both nodes exist but their values differ, return
false.Push their left children as one pair and their right children as another pair so corresponding positions remain aligned.
If every pair is processed without a mismatch, return
true.
Dry Run
Same Tree Appraoch 2 Dry Run.png
Solution
#include <bits/stdc++.h>using namespace std;struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int value) { val = value; left = nullptr; right = nullptr; }};class Solution {public: // Compares corresponding nodes // using breadth-first traversal. bool isSameTree(TreeNode* p, TreeNode* q) { queue<pair<TreeNode*, TreeNode*>> qNodes; // Start comparison from // the two root nodes. qNodes.push({p, q}); // Process one corresponding // node pair at a time. while (!qNodes.empty()) { auto [nodeP, nodeQ] = qNodes.front(); qNodes.pop(); // Both positions are empty, // so this pair matches. if (nodeP == nullptr && nodeQ == nullptr) { continue; } // Only one node exists, // so the structures differ. if (nodeP == nullptr || nodeQ == nullptr) { return false; } // Corresponding nodes must // contain the same value. if (nodeP->val != nodeQ->val) { return false; } // Keep corresponding children // paired for later comparison. qNodes.push({ nodeP->left, nodeQ->left }); qNodes.push({ nodeP->right, nodeQ->right }); } return true; }};int main() { TreeNode* p = new TreeNode(1); p->left = new TreeNode(2); p->right = new TreeNode(3); TreeNode* q = new TreeNode(1); q->left = new TreeNode(2); q->right = new TreeNode(3); Solution solution; cout << ( solution.isSameTree(p, q) ? "true" : "false" ) << endl; return 0;}Complexity Analysis
Time Complexity: O(N), where N is the number of nodes in either tree in the worst case. Every corresponding node pair is processed at most once.
Space Complexity: O(W), where W is the maximum width of the two trees. The queue may hold up to O(W) corresponding node pairs at the same time, which can become O(N) in the worst case.
Approach 3
Recursive DFS does not require level-order processing; it only needs corresponding positions from the two trees to remain paired.
The recursion stack can therefore be replaced with an explicit stack containing (nodeFromP, nodeFromQ) pairs. Each pair undergoes the same structural and value checks as in the recursive solution.
This avoids recursion while preserving the depth-first comparison order.
Algorithm
Push
(p, q)into a stack to begin comparison from the roots.Pop one pair at a time while the stack is not empty.
If both nodes are
null, continue; if exactly one isnull, returnfalse.If both nodes exist but their values differ, return
false.Push the corresponding right children first and the corresponding left children afterward, so the left pair is processed next and the traversal follows depth-first order.
If the stack becomes empty without finding any mismatch, return
true.
Dry Run
Same Tree Appraoch 3 Dry Run.png
Solution
#include <bits/stdc++.h>using namespace std;struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int value) { val = value; left = nullptr; right = nullptr; }};class Solution {public: // Compares corresponding nodes // using an explicit DFS stack. bool isSameTree(TreeNode* p, TreeNode* q) { stack<pair<TreeNode*, TreeNode*>> st; // Begin comparison from // the two root nodes. st.push({p, q}); // Process one corresponding // node pair at a time. while (!st.empty()) { auto [nodeP, nodeQ] = st.top(); st.pop(); // Both positions are empty, // so this pair matches. if (nodeP == nullptr && nodeQ == nullptr) { continue; } // Only one node exists, // so the structures differ. if (nodeP == nullptr || nodeQ == nullptr) { return false; } // Corresponding nodes must // contain the same value. if (nodeP->val != nodeQ->val) { return false; } // Push right first so // the left pair is checked next. st.push({ nodeP->right, nodeQ->right }); st.push({ nodeP->left, nodeQ->left }); } return true; }};int main() { TreeNode* p = new TreeNode(1); p->left = new TreeNode(2); p->right = new TreeNode(3); TreeNode* q = new TreeNode(1); q->left = new TreeNode(2); q->right = new TreeNode(3); Solution solution; cout << ( solution.isSameTree(p, q) ? "true" : "false" ) << endl; return 0;}Complexity Analysis
Time Complexity: O(N), where N is the number of nodes in either tree in the worst case. Every corresponding node pair is processed at most once.
Space Complexity: O(H), where H is the maximum height of the two trees. The explicit DFS stack can grow to O(H), which becomes O(N) for a skewed tree.
FAQs
Q1. Are two empty binary trees considered identical?
Yes. If both roots are null, both trees have the same empty structure, so they are identical.
Q2. Why must both structure and values be compared?
Equal values alone are not enough. A node may appear as a left child in one tree and a right child in the other, which means the structures are different.
Q3. Why can the algorithm return immediately after finding one mismatch?
Identical trees require every corresponding position to match. Therefore, a single structural or value mismatch is enough to prove that the trees are different.
Q4. Can tree serialization be used instead?
Yes. Both trees can be serialized with explicit null markers and the resulting representations can be compared. Direct node-by-node comparison is usually simpler and can stop as soon as a mismatch is found.
Q5. Which approach is preferable in interviews?
Recursive DFS is usually the simplest first solution because it directly mirrors the recursive definition of identical trees. BFS or iterative DFS are useful alternatives when recursion depth is a concern.
Be the first to add a comment.