Given the root
of a binary tree, check whether it is a mirror of itself (i.e., symmetric around its center).
Example 1:
Input: root = [1,2,2,3,4,4,3] Output: true
Example 2:
Input: root = [1,2,2,null,3,null,3] Output: false
Constraints:
[1, 1000]
.-100 <= Node.val <= 100
Follow up: Could you solve it both recursively and iteratively?
The core challenge of this problem is to determine if a binary tree is symmetric around its center. This means that the left subtree is a mirror reflection of the right subtree. This problem is significant in various applications such as validating data structures, ensuring balanced operations in algorithms, and more.
Potential pitfalls include misunderstanding the symmetry concept, especially when dealing with null nodes. A common misconception is that if the left and right subtrees have the same structure, they are symmetric, but their values must also mirror each other.
To solve this problem, we can use two main approaches: recursive and iterative.
The recursive approach involves checking if the left and right subtrees are mirrors of each other. This can be done by comparing the left child of the left subtree with the right child of the right subtree and vice versa.
The iterative approach uses a queue to perform a level-order traversal, ensuring that corresponding nodes in the left and right subtrees are mirrors of each other.
// Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
class Solution {
public:
bool isSymmetric(TreeNode* root) {
return isMirror(root, root);
}
private:
bool isMirror(TreeNode* t1, TreeNode* t2) {
if (t1 == nullptr && t2 == nullptr) return true;
if (t1 == nullptr || t2 == nullptr) return false;
return (t1->val == t2->val)
&& isMirror(t1->right, t2->left)
&& isMirror(t1->left, t2->right);
}
};
#include
// Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if (!root) return true;
std::queue q;
q.push(root->left);
q.push(root->right);
while (!q.empty()) {
TreeNode* t1 = q.front(); q.pop();
TreeNode* t2 = q.front(); q.pop();
if (!t1 && !t2) continue;
if (!t1 || !t2) return false;
if (t1->val != t2->val) return false;
q.push(t1->left);
q.push(t2->right);
q.push(t1->right);
q.push(t2->left);
}
return true;
}
};
Both the recursive and iterative solutions have a time complexity of O(n), where n is the number of nodes in the tree. This is because each node is visited once. The space complexity for the recursive solution is O(h), where h is the height of the tree, due to the recursion stack. For the iterative solution, the space complexity is O(n) due to the queue used for level-order traversal.
Potential edge cases include:
To test the solution comprehensively, consider the following test cases:
Using a testing framework like Google Test can help automate and validate these test cases.
When approaching such problems, it's essential to:
Understanding and solving the symmetric tree problem is crucial for mastering tree-based algorithms. By practicing both recursive and iterative approaches, you can enhance your problem-solving skills and prepare for more complex challenges.
For further reading and practice, consider the following resources: