Given the root of a binary tree, check whether it is a mirror of itself (i.e., symmetric around its center).
Input : root = [1, 2, 2, 3, 4, 4, 3]
Output : true
Explanation :
Input : root = [1, 2, 2, null, 3, null, 3]
Output : false
Explanation : When a straight line is drawn through the root node and the tree is folded around it, the rightmost node 3 is overlapped with null node and the node 3 present at left of root node is overlapped with null nodes.
So both node 3 in tree does not show symmetric behaviour.
Input: root = [1, 2, 3]
A tree is considered symmetric if its structure exhibits a mirroring pattern, where the left and right subtrees of each node are either identical or mirror images of each other. To verify the symmetry of a tree recursively, begin by comparing the root node's left and right subtrees. Then, for each pair of subtrees, ensure that the left child of the left subtree is a mirror image of the right child of the right subtree, and similarly, the right child of the left subtree mirrors the left child of the right subtree. This mirroring must be consistent throughout the entire tree to confirm its symmetry.
null
. If the tree is empty, return true
because an empty tree is symmetric by default.
null
, in which case the function should return true
. However, if only one subtree is null
while the other is not, return false
, as this indicates asymmetry.
true
. If any comparison fails, the function will return false
, indicating that the tree is not symmetric.
// Definition for a binary tree node.
struct TreeNode {
int data;
TreeNode *left;
TreeNode *right;
TreeNode(int val) : data(val), left(nullptr), right(nullptr) {}
};
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if (root == nullptr) {
return true; // An empty tree is symmetric
}
return symmetry(root->left, root->right);
}
private:
bool symmetry(TreeNode* left, TreeNode* right) {
if (left == nullptr && right == nullptr) {
return true; // Both nodes are null, so symmetric
}
if (left == nullptr || right == nullptr) {
return false; // One of the nodes is null, so not symmetric
}
if (left->data != right->data) {
return false; // The values of the nodes do not match, so not symmetric
}
// Recursively check the children of the nodes
return symmetry(left->left, right->right) && symmetry(left->right, right->left);
}
};
// Example usage
int main() {
Solution solution;
// Create a sample tree: 1, 2, 2, 3, 4, 4, 3
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(2);
root->left->left = new TreeNode(3);
root->left->right = new TreeNode(4);
root->right->left = new TreeNode(4);
root->right->right = new TreeNode(3);
// Test the symmetric tree
std::cout << std::boolalpha << solution.isSymmetric(root) << std::endl; // Output: true
return 0;
}
class TreeNode {
int data;
TreeNode left;
TreeNode right;
TreeNode(int val) {
this.data = val;
this.left = null;
this.right = null;
}
}
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root == null) {
return true; // An empty tree is symmetric
}
return symmetry(root.left, root.right);
}
private boolean symmetry(TreeNode left, TreeNode right) {
if (left == null && right == null) {
return true; // Both nodes are null, so symmetric
}
if (left == null || right == null) {
return false; // One of the nodes is null, so not symmetric
}
if (left.data != right.data) {
return false; // The values of the nodes do not match, so not symmetric
}
// Recursively check the children of the nodes
return symmetry(left.left, right.right) && symmetry(left.right, right.left);
}
public static void main(String[] args) {
Solution solution = new Solution();
// Create a sample tree: 1, 2, 2, 3, 4, 4, 3
TreeNode root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(2);
root.left.left = new TreeNode(3);
root.left.right = new TreeNode(4);
root.right.left = new TreeNode(4);
root.right.right = new TreeNode(3);
// Test the symmetric tree
System.out.println(solution.isSymmetric(root)); // Output: true
}
}
# Definition for a binary tree node.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.data = val
self.left = left
self.right = right
class Solution:
def is_symmetric(self, root):
if not root:
return True # An empty tree is symmetric
return self.symmetry(root.left, root.right)
def symmetry(self, left, right):
if not left and not right:
return True # Both nodes are null, so symmetric
if not left or not right:
return False # One of the nodes is null, so not symmetric
if left.data != right.data:
return False # The values of the nodes do not match, so not symmetric
# Recursively check the children of the nodes
return self.symmetry(left.left, right.right) and self.symmetry(left.right, right.left)
# Example usage
if __name__ == "__main__":
solution = Solution()
# Create a sample tree: 1, 2, 2, 3, 4, 4, 3
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(4)
root.right.right = TreeNode(3)
# Test the symmetric tree
print(solution.is_symmetric(root)) # Output: True
// Definition for a binary tree node.
class TreeNode {
constructor(val = 0, left = null, right = null) {
this.data = val;
this.left = left;
this.right = right;
}
}
class Solution {
isSymmetric(root) {
if (!root) {
return true; // An empty tree is symmetric
}
return this.symmetry(root.left, root.right);
}
symmetry(left, right) {
if (!left && !right) {
return true; // Both nodes are null, so symmetric
}
if (!left || !right) {
return false; // One of the nodes is null, so not symmetric
}
if (left.data !== right.data) {
return false; // The values of the nodes do not match, so not symmetric
}
// Recursively check the children of the nodes
return this.symmetry(left.left, right.right) && this.symmetry(left.right, right.left);
}
}
// Example usage
const solution = new Solution();
// Create a sample tree: 1, 2, 2, 3, 4, 4, 3
const root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(2);
root.left.left = new TreeNode(3);
root.left.right = new TreeNode(4);
root.right.left = new TreeNode(4);
root.right.right = new TreeNode(3);
// Test the symmetric tree
console.log(solution.isSymmetric(root)); // Output: true
Time complexity: O(N) This is because there are N number of nodes in the binary tree each node is traversed once to check for symmetry.
Space complexity : O(h) This is because the maximum depth of the recursion stack is equal to the height of the tree.
Q: How does this relate to palindrome structures?
A: A symmetric tree resembles a palindrome in tree form, where left and right halves mirror each other. Similar logic applies when checking symmetric strings or arrays.
Q: Why is a mirror check different from an identical tree check?
A: In an identical tree check, we compare corresponding nodes directly (left with left, right with right). In a mirror check, we compare left with right and right with left.
Q: What changes would be needed to find the largest symmetric subtree?
A: Use a bottom-up DFS approach, returning the largest symmetric subtree size while checking for symmetry at each node.
Q: Can this problem be solved using Morris traversal (O(1) space)?
A: Morris traversal works for inorder traversal, but symmetry checking requires level-based traversal, which Morris traversal doesn’t efficiently support.