Symmetric Tree

Check if a binary tree is symmetric around its center.

Language Selection

Choose your preferred programming language

Showing: Python

Symmetric Tree

Problem Statement

Given the root of a binary tree, check whether it is a mirror of itself (i.e., symmetric around its center).

Examples

Example 1:

Input: root = [1,2,2,3,4,4,3]
Output: true
Explanation: The tree is symmetric around its center.

Example 2:

Input: root = [1,2,2,null,3,null,3]
Output: false
Explanation: The tree is not symmetric.

Example 3:

Input: root = [1]
Output: true
Explanation: Single node tree is symmetric.

Constraints

  • The number of nodes in the tree is in the range [1, 1000].
  • -100 <= Node.val <= 100

Approach 1: Recursive DFS (Optimal)

Algorithm

Use recursion to check if left and right subtrees are mirrors of each other.

Steps:

  1. Check if root is null (symmetric)
  2. Recursively check if left and right subtrees are mirrors
  3. Two nodes are mirrors if:
    • Their values are equal
    • Left subtree of first node mirrors right subtree of second node
    • Right subtree of first node mirrors left subtree of second node

Implementation

Python:

def isSymmetric(root):
    """
    Check if binary tree is symmetric using recursive DFS
    Time: O(n)
    Space: O(h) where h is height of tree
    """
    if not root:
        return True
    
    def isMirror(left, right):
        if not left and not right:
            return True
        if not left or not right:
            return False
        if left.val != right.val:
            return False
        
        return (isMirror(left.left, right.right) and 
                isMirror(left.right, right.left))
    
    return isMirror(root.left, root.right)

Java:

class Solution {
    /**
     * Check if binary tree is symmetric using recursive DFS
     * Time: O(n)
     * Space: O(h) where h is height of tree
     */
    public boolean isSymmetric(TreeNode root) {
        if (root == null) {
            return true;
        }
        
        return isMirror(root.left, root.right);
    }
    
    private boolean isMirror(TreeNode left, TreeNode right) {
        if (left == null && right == null) {
            return true;
        }
        if (left == null || right == null) {
            return false;
        }
        if (left.val != right.val) {
            return false;
        }
        
        return isMirror(left.left, right.right) && 
               isMirror(left.right, right.left);
    }
}

Go:

func isSymmetric(root *TreeNode) bool {
    /**
     * Check if binary tree is symmetric using recursive DFS
     * Time: O(n)
     * Space: O(h) where h is height of tree
     */
    if root == nil {
        return true
    }
    
    return isMirror(root.Left, root.Right)
}

func isMirror(left, right *TreeNode) bool {
    if left == nil && right == nil {
        return true
    }
    if left == nil || right == nil {
        return false
    }
    if left.Val != right.Val {
        return false
    }
    
    return isMirror(left.Left, right.Right) && 
           isMirror(left.Right, right.Left)
}

JavaScript:

/**
 * Check if binary tree is symmetric using recursive DFS
 * Time: O(n)
 * Space: O(h) where h is height of tree
 */
function isSymmetric(root) {
    if (!root) {
        return true;
    }
    
    function isMirror(left, right) {
        if (!left && !right) {
            return true;
        }
        if (!left || !right) {
            return false;
        }
        if (left.val !== right.val) {
            return false;
        }
        
        return isMirror(left.left, right.right) && 
               isMirror(left.right, right.left);
    }
    
    return isMirror(root.left, root.right);
}

C#:

public class Solution {
    /// <summary>
    /// Check if binary tree is symmetric using recursive DFS
    /// Time: O(n)
    /// Space: O(h) where h is height of tree
    /// </summary>
    public bool IsSymmetric(TreeNode root) {
        if (root == null) {
            return true;
        }
        
        return IsMirror(root.left, root.right);
    }
    
    private bool IsMirror(TreeNode left, TreeNode right) {
        if (left == null && right == null) {
            return true;
        }
        if (left == null || right == null) {
            return false;
        }
        if (left.val != right.val) {
            return false;
        }
        
        return IsMirror(left.left, right.right) && 
               IsMirror(left.right, right.left);
    }
}

Complexity Analysis

  • Time Complexity: O(n) - Visit each node exactly once
  • Space Complexity: O(h) - Recursion stack depth equals tree height

Key Insights

  1. Mirror Property: Left and right subtrees must be mirrors
  2. Recursive Approach: Most intuitive and elegant solution
  3. Iterative Alternative: Use queue for BFS approach
  4. Null Handling: Both nodes must be null or both must be non-null
  5. Value Comparison: Node values must be equal for symmetry

Edge Cases

  1. Empty Tree: Should return true (symmetric)
  2. Single Node: Should return true (symmetric)
  3. Skewed Tree: Handle left-skewed or right-skewed trees
  4. Perfect Tree: Handle balanced trees efficiently
  5. Asymmetric Tree: Handle trees with different structures

Test Cases

def test_isSymmetric():
    # Test case 1: Symmetric tree
    root1 = TreeNode(1)
    root1.left = TreeNode(2)
    root1.right = TreeNode(2)
    root1.left.left = TreeNode(3)
    root1.left.right = TreeNode(4)
    root1.right.left = TreeNode(4)
    root1.right.right = TreeNode(3)
    
    assert isSymmetric(root1) == True
    
    # Test case 2: Asymmetric tree
    root2 = TreeNode(1)
    root2.left = TreeNode(2)
    root2.right = TreeNode(2)
    root2.left.right = TreeNode(3)
    root2.right.right = TreeNode(3)
    
    assert isSymmetric(root2) == False
    
    # Test case 3: Single node
    root3 = TreeNode(1)
    assert isSymmetric(root3) == True
    
    # Test case 4: Empty tree
    assert isSymmetric(None) == True
    
    print("All tests passed!")

test_isSymmetric()

Follow-up Questions

  1. Symmetric Tree II: Check symmetry for n-ary tree?
  2. Symmetric Tree with Values: Check symmetry ignoring values?
  3. Symmetric Tree with Structure: Check symmetry ignoring structure?
  4. Symmetric Tree with Paths: Check if all paths are symmetric?
  5. Symmetric Tree with Levels: Check symmetry level by level?

Common Mistakes

  1. Not Handling Nulls: Forgetting to check for null nodes
  2. Wrong Mirror Logic: Incorrectly comparing left-left with right-left
  3. Missing Base Cases: Not handling empty tree or single node
  4. Value Comparison: Not comparing node values for equality
  5. Recursion Depth: Not considering stack overflow for deep trees

Interview Tips

  1. Start with Recursion: Most intuitive approach
  2. Explain Mirror Logic: Show understanding of symmetry concept
  3. Handle Edge Cases: Mention empty tree and single node cases
  4. Discuss Trade-offs: Compare recursive vs iterative approaches
  5. Follow-up Ready: Be prepared for variations and optimizations

Concept Explanations

Symmetric Tree: A binary tree is symmetric if it is a mirror image of itself around its center. This means the left subtree is a mirror of the right subtree.

Mirror Property: Two nodes are mirrors if:

  • Their values are equal
  • The left subtree of the first node mirrors the right subtree of the second node
  • The right subtree of the first node mirrors the left subtree of the second node

Recursive Approach: We recursively check if the left and right subtrees are mirrors by comparing their values and recursively checking their children in mirror order.

Why Recursion Works: The problem has a recursive structure - if we can determine that two subtrees are mirrors, we can determine if the entire tree is symmetric.

Null Handling: We need to handle null nodes carefully. Two null nodes are considered mirrors, but a null node and a non-null node are not mirrors.