🧠
Brute Force (Recursive Mirror Check)
💡 Starting with recursion helps understand the problem deeply by directly comparing mirrored nodes, even though it may not be the most efficient approach.
Intuition
Check if the left and right subtrees are mirrors by recursively comparing the left child of one subtree with the right child of the other, and vice versa.
Algorithm
- If the root is null, return true (empty tree is symmetric).
- Define a helper function that takes two nodes and checks if they are mirrors.
- In the helper, if both nodes are null, return true.
- If one is null and the other is not, return false.
- Check if the values of the two nodes are equal.
- Recursively check if the left child of the first node is a mirror of the right child of the second node, and vice versa.
- Return true only if all above conditions hold.
💡 The recursion is tricky because it compares nodes across subtrees in a mirrored way, not just straightforward left-to-left or right-to-right.
from collections import deque
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def isSymmetric(root):
def isMirror(t1, t2):
if not t1 and not t2:
return True
if not t1 or not t2:
return False
return (t1.val == t2.val) and isMirror(t1.left, t2.right) and isMirror(t1.right, t2.left)
return isMirror(root, root)
# Example usage:
# root = TreeNode(1, TreeNode(2), TreeNode(2))
# print(isSymmetric(root))
Line Notes
def isMirror(t1, t2):Defines the recursive helper to compare two nodes for mirror symmetry
if not t1 and not t2:Base case: both nodes are null means symmetric at this branch
if not t1 or not t2:If only one node is null, symmetry breaks here
return (t1.val == t2.val) and isMirror(t1.left, t2.right) and isMirror(t1.right, t2.left)Check current node values and recurse on mirrored children
import java.util.*;
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int x) { val = x; }
}
public class Solution {
public boolean isSymmetric(TreeNode root) {
return isMirror(root, root);
}
private boolean isMirror(TreeNode t1, TreeNode t2) {
if (t1 == null && t2 == null) return true;
if (t1 == null || t2 == null) return false;
return (t1.val == t2.val) && isMirror(t1.left, t2.right) && isMirror(t1.right, t2.left);
}
// Example main
public static void main(String[] args) {
TreeNode root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(2);
System.out.println(new Solution().isSymmetric(root));
}
}
Line Notes
public boolean isSymmetric(TreeNode root)Entry point that starts mirror check from root with itself
if (t1 == null && t2 == null) return true;Both nodes null means symmetric at this subtree
if (t1 == null || t2 == null) return false;One null breaks symmetry
return (t1.val == t2.val) && isMirror(t1.left, t2.right) && isMirror(t1.right, t2.left);Check values and recurse on mirrored children
#include <iostream>
using namespace std;
struct TreeNode {
int val;
TreeNode *left, *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
public:
bool isSymmetric(TreeNode* root) {
return isMirror(root, root);
}
private:
bool isMirror(TreeNode* t1, TreeNode* t2) {
if (!t1 && !t2) return true;
if (!t1 || !t2) return false;
return (t1->val == t2->val) && isMirror(t1->left, t2->right) && isMirror(t1->right, t2->left);
}
};
// Example usage
int main() {
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(2);
Solution sol;
cout << (sol.isSymmetric(root) ? "true" : "false") << endl;
return 0;
}
Line Notes
bool isMirror(TreeNode* t1, TreeNode* t2)Helper function to recursively check mirrored nodes
if (!t1 && !t2) return true;Both null means symmetric at this branch
if (!t1 || !t2) return false;One null breaks symmetry
return (t1->val == t2->val) && isMirror(t1->left, t2->right) && isMirror(t1->right, t2->left);Check values and recurse on mirrored children
function TreeNode(val, left=null, right=null) {
this.val = val;
this.left = left;
this.right = right;
}
var isSymmetric = function(root) {
function isMirror(t1, t2) {
if (!t1 && !t2) return true;
if (!t1 || !t2) return false;
return (t1.val === t2.val) && isMirror(t1.left, t2.right) && isMirror(t1.right, t2.left);
}
return isMirror(root, root);
};
// Example usage:
// let root = new TreeNode(1, new TreeNode(2), new TreeNode(2));
// console.log(isSymmetric(root));
Line Notes
function isMirror(t1, t2)Recursive helper to check if two nodes are mirrors
if (!t1 && !t2) return true;Both null nodes mean symmetry at this point
if (!t1 || !t2) return false;One null node breaks symmetry
return (t1.val === t2.val) && isMirror(t1.left, t2.right) && isMirror(t1.right, t2.left);Check values and recurse on mirrored children
Each node is visited once; recursion stack can go as deep as tree height h
💡 For n=1000 nodes and balanced tree height ~10, about 1000 operations and stack depth 10
Interview Verdict: Accepted
This approach is accepted and intuitive, but recursion stack can be large for very deep trees.