101. Symmetric Tree
On LeetCode ->Reformulated question¶
Given a binary tree root, return True if its left and right subtrees are mirror images of each other.
Example:
Key trick¶
Compare nodes in pairs that must mirror each other:
a.val == b.vala.leftmirrorsb.righta.rightmirrorsb.left
Trap¶
- Comparing only values per level is not enough.
- Ignoring
Nonepositions gives false positives. - Accessing
root.leftwhenrootisNoneis unsafe outside LeetCode-style assumptions.
Why is this question interesting?¶
It tests whether you see tree symmetry as a two-pointer problem on trees:
- left side walks outward one way
- right side walks outward the opposite way
Solve the problem with idiomatic python¶
from utils import TreeNode
from typing import Optional
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
def mirror(a: Optional[TreeNode], b: Optional[TreeNode]) -> bool:
# both missing: symmetric here
if a is None and b is None:
return True
# exactly one missing or different values: not symmetric
if a is None or b is None or a.val != b.val:
return False
# outer children must match, and inner children must match
return mirror(a.left, b.right) and mirror(a.right, b.left)
return True if root is None else mirror(root.left, root.right)
- This is the standard direct solution.
- Time is \(O(n)\) and recursion stack is \(O(h)\).
Pytest test¶
from utils import tree_build
from typing import Optional
import pytest
@pytest.mark.parametrize(
("values", "expected"),
[
([1], True),
([1, 2, 2], True),
([1, 2, 2, 3, 4, 4, 3], True),
([1, 2, 2, None, 3, None, 3], False),
([1, 2, 2, None, 3, 3, None], True),
([1, 2, 2, 3, None, None, 3], True),
([1, 2, 2, 3, None, 3, None], False),
([1, 2, 3], False),
],
)
def test_is_symmetric(values, expected):
root = tree_build(values)
assert Solution().isSymmetric(root) is expected
Comment my solution¶
Your solution works much harder than needed.
- The path-tracking idea is unnecessary.
- Symmetry is local and recursive, so storing full paths adds avoidable complexity.
- It does not represent missing children explicitly, which is the usual bug source in level-based approaches.
if root.left is None and root.right is None:assumesrootexists.- The helper
is_sym_nodechecks path complementarity, but mirror recursion already encodes that more simply and safely.
A simpler and more interview-friendly version is the recursive mirror check above.
from utils import TreeNode, tree_build
from typing import Optional
import pytest
from collections import deque
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
# The number of nodes in the tree is in the range `[1, 1000]`.
if root.left is None and root.right is None:
return True
if not (root.left and root.right):
return False
def is_sym_node(node_path1, node_path2):
n1, p1 = node_path1
n2, p2 = node_path2
if n1.val != n2.val:
return False
if len(p1) != len(p2):
return False
for i in range(len(p1)):
if p1[i] ^ p2[i] == 0:
return False
return True
# (node, path) where path is array of [0,1,0,1] 0 for left, 1 for right
# nodes are symmetric if path1 symmetric of path2
nodes_same_level = [(root.left, [0]), (root.right, [1])]
while nodes_same_level:
if len(nodes_same_level) % 2 != 0:
return False
next_level_left = []
next_level_right = deque([])
left_idx, right_idx = 0, len(nodes_same_level) - 1
while left_idx < right_idx:
left = nodes_same_level[left_idx]
right = nodes_same_level[right_idx]
if not is_sym_node(left, right):
return False
left_node, left_path = left[0], left[1]
if left_node.left:
next_level_left.append((left_node.left, left_path + [0]))
if left_node.right:
next_level_left.append((left_node.right, left_path + [1]))
right_node, right_path = right[0], right[1]
if right_node.right:
next_level_right.appendleft((right_node.right, right_path + [1]))
if right_node.left:
next_level_right.appendleft((right_node.left, right_path + [0]))
left_idx += 1
right_idx -= 1
nodes_same_level = next_level_left + list(next_level_right)
return True
class SolutionRecursive:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
# Implemented after reading comments from AI
def is_sym_level(level):
if not any(level):
return True
n = len(level)
next_level = []
for i in range(n):
if i < (n // 2):
n1 = level[i].val if level[i] else None
n2 = level[n - 1 - i].val if level[n - 1 - i] else None
if n1 != n2:
return False
next_left = None if level[i] is None else level[i].left
next_right = None if level[i] is None else level[i].right
next_level.append(next_left)
next_level.append(next_right)
return is_sym_level(next_level)
return is_sym_level([root])
@pytest.mark.parametrize(
("values", "is_symmetric"),
[
([1], True),
([1,2,2,3,4,4,3], True),
([1,2,2,None,3,None,3], False),
([1,2,3], False)
],
)
def test_isSymmetric(values, is_symmetric):
root = tree_build(values)
assert Solution().isSymmetric(root) == is_symmetric
assert SolutionRecursive().isSymmetric(root) == is_symmetric