226. Invert Binary Tree - Explanation

Problem Link

Description

You are given the root of a binary tree root. Invert the binary tree and return its root.

Example 1:

Input: root = [1,2,3,4,5,6,7]

Output: [1,3,2,7,6,5,4]

Example 2:

Input: root = [3,2,1]

Output: [3,1,2]

Example 3:

Input: root = []

Output: []

Constraints:

  • 0 <= The number of nodes in the tree <= 100.
  • -100 <= Node.val <= 100


Topics

Recommended Time & Space Complexity

You should aim for a solution with O(n) time and O(n) space, where n is the number of nodes in the tree.


Hint 1

From the diagram, you can see that the left and right children of every node in the tree are swapped. Can you think of a way to achieve this recursively? Maybe an algorithm that is helpful to traverse the tree.


Hint 2

We can use the Depth First Search (DFS) algorithm. At each node, we swap its left and right children by swapping their pointers. This inverts the current node, but every node in the tree also needs to be inverted. To achieve this, we recursively visit the left and right children and perform the same operation. If the current node is null, we simply return.


Company Tags


Prerequisites

Before attempting this problem, you should be comfortable with:

  • Binary Trees - Understanding tree node structure with left and right children
  • Breadth-First Search (BFS) - Level-by-level traversal using a queue
  • Depth-First Search (DFS) - Recursive traversal of tree structures
  • Stack-based Iteration - Converting recursive DFS to iterative form using an explicit stack

Intuition

To invert (mirror) a binary tree, every node must swap its left and right children. Using Breadth-First Search (BFS), we process the tree level-by-level:

  • Start from the root.
  • For each node, swap its children.
  • Then push the (new) left and right children into the queue.
  • Continue until every node has been processed.

This approach ensures that every node is visited exactly once and inverted immediately when encountered.


Algorithm

  1. If the tree is empty, return null.
  2. Initialize a queue and insert the root node.
  3. While the queue is not empty:
    • Remove the front node.
    • Swap its left and right children.
    • If the left child exists, add it to the queue.
    • If the right child exists, add it to the queue.
  4. After all nodes are processed, return the root as the inverted tree.
Example - Dry Run
Input Tree:
               ┌───┐
               │ 4 │
               └─┬─┘
         ┌───────┴───────┐
       ┌─┴─┐           ┌─┴─┐
       │ 2 │           │ 7 │
       └─┬─┘           └─┬─┘
      ┌──┴──┐         ┌──┴──┐
    ┌─┴─┐ ┌─┴─┐     ┌─┴─┐ ┌─┴─┐
    │ 1 │ │ 3 │     │ 6 │ │ 9 │
    └───┘ └───┘     └───┘ └───┘

Queue: [4]

BFS Traversal (Level by Level):

Step 1: Dequeue node 4, swap its children (2 <-> 7)

  Swap children of node 4:

      Before:              After:
         4                    4
        / \                  / \
       2   7        →       7   2


  Current state:
               ┌───┐
               │ 4 │
               └─┬─┘
         ┌───────┴───────┐
       ┌─┴─┐           ┌─┴─┐
       │ 7 │           │ 2 │  ← swapped!
       └─┬─┘           └─┬─┘
      ┌──┴──┐         ┌──┴──┐
    ┌─┴─┐ ┌─┴─┐     ┌─┴─┐ ┌─┴─┐
    │ 6 │ │ 9 │     │ 1 │ │ 3 │
    └───┘ └───┘     └───┘ └───┘

  Queue: [7, 2]

Step 2: Dequeue node 7, swap its children (6 <-> 9)

  Swap children of node 7:

      Before:              After:
         7                    7
        / \                  / \
       6   9        →       9   6


  Current state:
               ┌───┐
               │ 4 │
               └─┬─┘
         ┌───────┴───────┐
       ┌─┴─┐           ┌─┴─┐
       │ 7 │           │ 2 │
       └─┬─┘           └─┬─┘
      ┌──┴──┐         ┌──┴──┐
    ┌─┴─┐ ┌─┴─┐     ┌─┴─┐ ┌─┴─┐
    │ 9 │ │ 6 │     │ 1 │ │ 3 │  ← swapped 9,6!
    └───┘ └───┘     └───┘ └───┘

  Queue: [2, 9, 6]

Step 3: Dequeue node 2, swap its children (1 <-> 3)

  Swap children of node 2:

      Before:              After:
         2                    2
        / \                  / \
       1   3        →       3   1


  Current state:
               ┌───┐
               │ 4 │
               └─┬─┘
         ┌───────┴───────┐
       ┌─┴─┐           ┌─┴─┐
       │ 7 │           │ 2 │
       └─┬─┘           └─┬─┘
      ┌──┴──┐         ┌──┴──┐
    ┌─┴─┐ ┌─┴─┐     ┌─┴─┐ ┌─┴─┐
    │ 9 │ │ 6 │     │ 3 │ │ 1 │  ← swapped 3,1!
    └───┘ └───┘     └───┘ └───┘

  Queue: [9, 6, 3, 1]

Steps 4-7: Dequeue nodes 9, 6, 3, 1

  All are leaf nodes (no children to swap)

  Queue: [] (empty)

Final Inverted Tree:

               ┌───┐
               │ 4 │
               └─┬─┘
         ┌───────┴───────┐
       ┌─┴─┐           ┌─┴─┐
       │ 7 │           │ 2 │
       └─┬─┘           └─┬─┘
      ┌──┴──┐         ┌──┴──┐
    ┌─┴─┐ ┌─┴─┐     ┌─┴─┐ ┌─┴─┐
    │ 9 │ │ 6 │     │ 3 │ │ 1 │
    └───┘ └───┘     └───┘ └───┘

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right

class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if not root:
            return None
        queue = deque([root])
        while queue:
            node = queue.popleft()
            node.left, node.right = node.right, node.left
            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)
        return root

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n)

Intuition

Inverting a binary tree means swapping every node’s left and right subtree.
With Depth-First Search (DFS), we use recursion to invert the tree in a top-down manner:

  • At each node, swap the left and right children.
  • Then recursively invert the left subtree.
  • Recursively invert the right subtree.

Because every subtree is itself a smaller binary tree, recursion naturally handles this structure.
The inversion happens during the descent of the recursion, and each subtree becomes correctly mirrored.


Algorithm

  1. If the current node is null, return null.
  2. Swap the node's left and right pointers.
  3. Recursively call dfs on the new left child.
  4. Recursively call dfs on the new right child.
  5. Return the current node (now inverted).
Example - Dry Run
Input Tree:
               ┌───┐
               │ 4 │
               └─┬─┘
         ┌───────┴───────┐
       ┌─┴─┐           ┌─┴─┐
       │ 2 │           │ 7 │
       └─┬─┘           └─┬─┘
      ┌──┴──┐         ┌──┴──┐
    ┌─┴─┐ ┌─┴─┐     ┌─┴─┐ ┌─┴─┐
    │ 1 │ │ 3 │     │ 6 │ │ 9 │
    └───┘ └───┘     └───┘ └───┘

DFS Recursive Traversal (Top-Down):

Call 1: invertTree(4)

  Swap children of node 4:

      Before:              After:
         4                    4
        / \                  / \
       2   7        →       7   2


  Current state:
               ┌───┐
               │ 4 │  ← processing
               └─┬─┘
         ┌───────┴───────┐
       ┌─┴─┐           ┌─┴─┐
       │ 7 │           │ 2 │  ← swapped!
       └─┬─┘           └─┬─┘
      ┌──┴──┐         ┌──┴──┐
    ┌─┴─┐ ┌─┴─┐     ┌─┴─┐ ┌─┴─┐
    │ 6 │ │ 9 │     │ 1 │ │ 3 │
    └───┘ └───┘     └───┘ └───┘

  → Recurse on left child (now 7)

Call 2: invertTree(7)

  Swap children of node 7:

      Before:              After:
         7                    7
        / \                  / \
       6   9        →       9   6


  Current state:
               ┌───┐
               │ 4 │
               └─┬─┘
         ┌───────┴───────┐
       ┌─┴─┐           ┌─┴─┐
       │ 7 │           │ 2 │
       └─┬─┘           └─┬─┘
      ┌──┴──┐         ┌──┴──┐
    ┌─┴─┐ ┌─┴─┐     ┌─┴─┐ ┌─┴─┐
    │ 9 │ │ 6 │     │ 1 │ │ 3 │  ← swapped 9,6!
    └───┘ └───┘     └───┘ └───┘

  → Recurse on left child (now 9)

Call 3: invertTree(9)

  Node 9 is a leaf (no children to swap)

    ┌───┐
    │ 9 │  ← leaf node, nothing to swap
    └───┘

  → Return to Call 2

Call 4: invertTree(6)

  Node 6 is a leaf (no children to swap)

    ┌───┐
    │ 6 │  ← leaf node, nothing to swap
    └───┘

  → Return to Call 2, then return to Call 1

Call 5: invertTree(2)

  Swap children of node 2:

      Before:              After:
         2                    2
        / \                  / \
       1   3        →       3   1


  Current state:
               ┌───┐
               │ 4 │
               └─┬─┘
         ┌───────┴───────┐
       ┌─┴─┐           ┌─┴─┐
       │ 7 │           │ 2 │  ← processing
       └─┬─┘           └─┬─┘
      ┌──┴──┐         ┌──┴──┐
    ┌─┴─┐ ┌─┴─┐     ┌─┴─┐ ┌─┴─┐
    │ 9 │ │ 6 │     │ 3 │ │ 1 │  ← swapped 3,1!
    └───┘ └───┘     └───┘ └───┘

  → Recurse on left child (now 3)

Call 6: invertTree(3)

  Node 3 is a leaf (no children to swap)

    ┌───┐
    │ 3 │  ← leaf node, nothing to swap
    └───┘

  → Return to Call 5

Call 7: invertTree(1)

  Node 1 is a leaf (no children to swap)

    ┌───┐
    │ 1 │  ← leaf node, nothing to swap
    └───┘

  → Return to Call 5, then return to Call 1

Final Inverted Tree:

               ┌───┐
               │ 4 │
               └─┬─┘
         ┌───────┴───────┐
       ┌─┴─┐           ┌─┴─┐
       │ 7 │           │ 2 │
       └─┬─┘           └─┬─┘
      ┌──┴──┐         ┌──┴──┐
    ┌─┴─┐ ┌─┴─┐     ┌─┴─┐ ┌─┴─┐
    │ 9 │ │ 6 │     │ 3 │ │ 1 │
    └───┘ └───┘     └───┘ └───┘

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right

class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if not root: return None

        root.left, root.right = root.right, root.left

        self.invertTree(root.left)
        self.invertTree(root.right)

        return root

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n) for recursion stack.

3. Iterative DFS

Intuition

Iterative DFS inverts a binary tree using an explicit stack instead of recursion.
The idea is the same as recursive DFS:

  • Visit a node.
  • Swap its left and right children.
  • Continue the process for its children.

But instead of the call stack, we use our own stack data structure.

The process is:

  1. Push the root into the stack.
  2. Pop the top node, swap its children.
  3. Push its children onto the stack (if they exist).
  4. Continue until the stack is empty.

This simulates the recursive DFS in an iterative manner and works well when recursion depth may be too large.


Algorithm

  1. If root is null, return null.
  2. Initialize a stack with root.
  3. While stack is not empty:
    • Pop a node.
    • Swap its left and right pointers.
    • If the left child exists, push it to the stack.
    • If the right child exists, push it to the stack.
  4. Return the root.
Example - Dry Run
Input Tree:
               ┌───┐
               │ 4 │
               └─┬─┘
         ┌───────┴───────┐
       ┌─┴─┐           ┌─┴─┐
       │ 2 │           │ 7 │
       └─┬─┘           └─┬─┘
      ┌──┴──┐         ┌──┴──┐
    ┌─┴─┐ ┌─┴─┐     ┌─┴─┐ ┌─┴─┐
    │ 1 │ │ 3 │     │ 6 │ │ 9 │
    └───┘ └───┘     └───┘ └───┘

Stack: [4]

Iterative DFS using Stack:

Step 1: Pop node 4, swap its children (2 <-> 7)

  Swap children of node 4:

      Before:              After:
         4                    4
        / \                  / \
       2   7        →       7   2


  Current state:
               ┌───┐
               │ 4 │
               └─┬─┘
         ┌───────┴───────┐
       ┌─┴─┐           ┌─┴─┐
       │ 7 │           │ 2 │  ← swapped!
       └─┬─┘           └─┬─┘
      ┌──┴──┐         ┌──┴──┐
    ┌─┴─┐ ┌─┴─┐     ┌─┴─┐ ┌─┴─┐
    │ 6 │ │ 9 │     │ 1 │ │ 3 │
    └───┘ └───┘     └───┘ └───┘

  Stack: [7, 2]  (pushed children)

Step 2: Pop node 2, swap its children (1 <-> 3)

  Swap children of node 2:

      Before:              After:
         2                    2
        / \                  / \
       1   3        →       3   1


  Current state:
               ┌───┐
               │ 4 │
               └─┬─┘
         ┌───────┴───────┐
       ┌─┴─┐           ┌─┴─┐
       │ 7 │           │ 2 │  ← processing
       └─┬─┘           └─┬─┘
      ┌──┴──┐         ┌──┴──┐
    ┌─┴─┐ ┌─┴─┐     ┌─┴─┐ ┌─┴─┐
    │ 6 │ │ 9 │     │ 3 │ │ 1 │  ← swapped 3,1!
    └───┘ └───┘     └───┘ └───┘

  Stack: [7, 3, 1]  (pushed children)

Step 3: Pop node 1 (leaf node)

  Node 1 is a leaf (no children to swap)

    ┌───┐
    │ 1 │  ← leaf node, nothing to swap
    └───┘

  Stack: [7, 3]

Step 4: Pop node 3 (leaf node)

  Node 3 is a leaf (no children to swap)

    ┌───┐
    │ 3 │  ← leaf node, nothing to swap
    └───┘

  Stack: [7]

Step 5: Pop node 7, swap its children (6 <-> 9)

  Swap children of node 7:

      Before:              After:
         7                    7
        / \                  / \
       6   9        →       9   6


  Current state:
               ┌───┐
               │ 4 │
               └─┬─┘
         ┌───────┴───────┐
       ┌─┴─┐           ┌─┴─┐
       │ 7 │           │ 2 │
       └─┬─┘           └─┬─┘
      ┌──┴──┐         ┌──┴──┐
    ┌─┴─┐ ┌─┴─┐     ┌─┴─┐ ┌─┴─┐
    │ 9 │ │ 6 │     │ 3 │ │ 1 │  ← swapped 9,6!
    └───┘ └───┘     └───┘ └───┘

  Stack: [9, 6]  (pushed children)

Step 6: Pop node 6 (leaf node)

  Node 6 is a leaf (no children to swap)

    ┌───┐
    │ 6 │  ← leaf node, nothing to swap
    └───┘

  Stack: [9]

Step 7: Pop node 9 (leaf node)

  Node 9 is a leaf (no children to swap)

    ┌───┐
    │ 9 │  ← leaf node, nothing to swap
    └───┘

  Stack: [] (empty)

Final Inverted Tree:

               ┌───┐
               │ 4 │
               └─┬─┘
         ┌───────┴───────┐
       ┌─┴─┐           ┌─┴─┐
       │ 7 │           │ 2 │
       └─┬─┘           └─┬─┘
      ┌──┴──┐         ┌──┴──┐
    ┌─┴─┐ ┌─┴─┐     ┌─┴─┐ ┌─┴─┐
    │ 9 │ │ 6 │     │ 3 │ │ 1 │
    └───┘ └───┘     └───┘ └───┘

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right

class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if not root:
            return None
        stack = [root]
        while stack:
            node = stack.pop()
            node.left, node.right = node.right, node.left
            if node.left:
                stack.append(node.left)
            if node.right:
                stack.append(node.right)
        return root

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n)

Common Pitfalls

Not Handling Null Root

Forgetting to check for a null root causes null pointer exceptions. Always return null immediately if the root is null.

Swapping After Recursive Calls

If you swap children after making recursive calls, you end up swapping already-inverted subtrees back. The swap must happen before or the recursion will undo the inversion.

# Wrong: swaps after recursion undoes the inversion
self.invertTree(root.left)
self.invertTree(root.right)
root.left, root.right = root.right, root.left
# Correct: swap first, then recurse
root.left, root.right = root.right, root.left
self.invertTree(root.left)
self.invertTree(root.right)

Using Wrong References After Swap

After swapping, root.left now points to what was previously root.right. When recursing, make sure you're using the correct references for the swapped children.

Modifying While Traversing Incorrectly

In iterative approaches, ensure you push children to the stack after swapping, not before. Pushing before the swap means you're adding references to positions that will change.