Problem Statement
Given two binary trees, write a function to check if they are structurally identical and have the same node values.
Examples
Example 1:
Consider two binary trees:
Tree 1:
1
/ \
2 3
Tree 2:
1
/ \
2 3
The function should return true since both trees are identical in structure and node values.
Input: p = [1,2,3], q = [1,2,3]
Output: true
Different Approaches
1 Recursive Approach:
- Traverse both trees simultaneously.
- At each step, compare the current nodes' values and
- recursively check their left and right subtrees.
- If at any point, the values are not equal or the structures differ, return false.
- If both trees are fully traversed and no differences are found, return true.
2 Iterative Approach using Stack
- Perform iterative preorder traversal on both trees using stacks.
- At each step, compare the current nodes' values and push their children onto the stack.
- If the values are not equal or one tree has a child while the other does not, return false.
- If both stacks are empty and no differences are found, return true.
Code Implementation
1 Recursive:
#include <iostream>
#include <stack>
using namespace std;
// Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if (!p && !q) return true; // Both trees are empty
if (!p || !q) return false; // One tree is empty, the other is not
if (p->val != q->val) return false; // Nodes have different values
return isSameTree(p->left, q->left) && isSameTree(p->right, q->right); // Recursively check left and right subtrees
}
};
int main() {
Solution solution;
// Example usage
TreeNode* tree1 = new TreeNode(1);
tree1->left = new TreeNode(2);
tree1->right = new TreeNode(3);
TreeNode* tree2 = new TreeNode(1);
tree2->left = new TreeNode(2);
tree2->right = new TreeNode(3);
cout << "Are the trees the same? " << (solution.isSameTree(tree1, tree2) ? "Yes" : "No") << endl;
return 0;
}
Explanation:
- If both p and q are NULL, indicating empty trees, we return true as they are considered identical.
- If one of p or q is NULL while the other is not, the trees are structurally different, so we return false.
- If the values of the current nodes p and q are different, the trees cannot be identical, so we return false.
- Otherwise, we recursively call
isSameTree
for the left and right subtrees of both p and q. If both recursive calls return true, indicating that the corresponding subtrees are identical, we return true; otherwise, we return false.
2 Iterative Approach using Stack:
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
stack<TreeNode*> stackP, stackQ;
stackP.push(p);
stackQ.push(q);
while (!stackP.empty() && !stackQ.empty()) {
TreeNode* nodeP = stackP.top();
TreeNode* nodeQ = stackQ.top();
stackP.pop();
stackQ.pop();
if (!nodeP && !nodeQ) continue; // Both nodes are empty, continue to next iteration
if (!nodeP || !nodeQ || nodeP->val != nodeQ->val) return false; // Nodes are not identical
stackP.push(nodeP->right); // Push right children onto stack
stackP.push(nodeP->left); // Push left children onto stack
stackQ.push(nodeQ->right); // Push right children onto stack
stackQ.push(nodeQ->left); // Push left children onto stack
}
return stackP.empty() && stackQ.empty(); // Both stacks should be empty for trees to be identical
}
};
Explanation:
- We define a class Solution containing the function
isSameTree
, which takes pointers to the root nodes of two binary trees (p
andq
) as arguments. - We use two stacks (
stackP
andstackQ
) to perform iterative preorder traversal simultaneously on both trees. - We push the root nodes of both trees onto their respective stacks to initiate traversal.
- While both stacks are not empty:
- Pop the top nodes (
nodeP
andnodeQ
) from both stacks. - If both nodes are empty, continue to the next iteration.
- If one node is empty while the other is not, or their values are not equal, return false.
- Push the right and left children of both nodes onto their respective stacks for traversal.
- Pop the top nodes (
- After the traversal is complete, both stacks should be empty for the trees to be identical.
Complexity Analysis
1 Recursive Approach:
- Time Complexity:
O(n)
, wheren
is the number of nodes in the smaller tree. - Space Complexity:
O(h)
, whereh
is the height of the tree due to recursive calls on the stack.
2 Iterative Approach using Stack:
- Time Complexity:
O(n)
, wheren
is the number of nodes in the smaller tree. - Space Complexity:
O(h)
, whereh
is the height of the tree due to the stack space used for traversal.