A clear explanation of inverting a binary tree using recursive depth-first traversal.
Problem Restatement
We are given the root of a binary tree.
We need to invert the tree and return its root. Inverting means every node swaps its left child and right child.
For example, LeetCode gives this input and output: root = [4,2,7,1,3,6,9] becomes [4,7,2,9,6,3,1]. The constraints say the tree has between 0 and 100 nodes, and each node value is between -100 and 100.
Input and Output
| Item | Meaning |
|---|---|
| Input | root, the root node of a binary tree |
| Output | The root of the inverted binary tree |
| Empty tree | Return None |
| Operation | Swap the left and right child of every node |
LeetCode gives the usual binary tree node shape:
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = rightThe required function shape is:
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
...Examples
Example 1:
Input: root = [4,2,7,1,3,6,9]
Output: [4,7,2,9,6,3,1]The original tree is:
4
/ \
2 7
/ \ / \
1 3 6 9After inversion:
4
/ \
7 2
/ \ / \
9 6 3 1Every node swapped its left and right children.
Example 2:
Input: root = [2,1,3]
Output: [2,3,1]Original:
2
/ \
1 3Inverted:
2
/ \
3 1Example 3:
Input: root = []
Output: []An empty tree stays empty.
First Thought: Traverse Every Node
To invert the whole tree, every node must be visited once.
At each node, we only need one local operation:
swap node.left and node.rightThe question becomes: how do we visit every node?
A binary tree naturally supports recursive traversal. Each subtree is itself a smaller binary tree.
So the same operation works for:
- The root.
- The left subtree.
- The right subtree.
Key Insight
To invert a tree rooted at root, we can do this:
- Invert the left subtree.
- Invert the right subtree.
- Swap the two inverted subtrees.
The base case is an empty tree.
If root is None, there is nothing to invert, so we return None.
This gives a very small recursive solution.
Algorithm
For a node root:
- If
rootisNone, returnNone. - Recursively invert
root.left. - Recursively invert
root.right. - Swap
root.leftandroot.right. - Return
root.
In Python, the swap can be written directly:
root.left, root.right = root.right, root.leftThen we continue recursively into the children.
There are two equivalent orders:
root.left, root.right = root.right, root.left
self.invertTree(root.left)
self.invertTree(root.right)or:
left = self.invertTree(root.left)
right = self.invertTree(root.right)
root.left = right
root.right = leftBoth are correct. The second version makes the recursive structure more explicit, so we will use it.
Correctness
We prove the algorithm is correct by induction on the size of the tree.
For an empty tree, the algorithm returns None. This is correct because the inverse of an empty tree is still empty.
Now consider a non-empty tree with root root.
Assume the algorithm correctly inverts the left subtree and the right subtree. This is the induction hypothesis.
The algorithm first computes:
left = self.invertTree(root.left)
right = self.invertTree(root.right)By the induction hypothesis, left is the inverted original left subtree, and right is the inverted original right subtree.
Then the algorithm assigns:
root.left = right
root.right = leftThis places the inverted original right subtree on the left side, and the inverted original left subtree on the right side.
That is exactly the definition of a mirrored binary tree.
Therefore, the tree rooted at root is correctly inverted. By induction, the algorithm correctly inverts the whole tree.
Complexity
| Metric | Value | Why |
|---|---|---|
| Time | O(n) | Each node is visited once |
| Space | O(h) | The recursion stack has depth equal to the tree height |
Here, n is the number of nodes, and h is the height of the tree.
For a balanced tree, h = O(log n).
For a skewed tree, h = O(n).
Implementation
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if root is None:
return None
left = self.invertTree(root.left)
right = self.invertTree(root.right)
root.left = right
root.right = left
return rootCode Explanation
The base case handles an empty subtree:
if root is None:
return NoneThis also handles the case where the whole input tree is empty.
Then we recursively invert both children:
left = self.invertTree(root.left)
right = self.invertTree(root.right)After these calls finish, left and right already point to inverted subtrees.
Now we swap them:
root.left = right
root.right = leftFinally, we return the current root:
return rootThe root node itself does not change. Only its child pointers change.
Testing
To test tree problems, it helps to convert between list representation and tree representation.
from collections import deque
from typing import Optional
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def build_tree(values):
if not values:
return None
root = TreeNode(values[0])
q = deque([root])
i = 1
while q and i < len(values):
node = q.popleft()
if i < len(values) and values[i] is not None:
node.left = TreeNode(values[i])
q.append(node.left)
i += 1
if i < len(values) and values[i] is not None:
node.right = TreeNode(values[i])
q.append(node.right)
i += 1
return root
def tree_to_list(root):
if root is None:
return []
result = []
q = deque([root])
while q:
node = q.popleft()
if node is None:
result.append(None)
continue
result.append(node.val)
q.append(node.left)
q.append(node.right)
while result and result[-1] is None:
result.pop()
return resultNow we can test the solution:
def run_tests():
s = Solution()
root = build_tree([4, 2, 7, 1, 3, 6, 9])
assert tree_to_list(s.invertTree(root)) == [4, 7, 2, 9, 6, 3, 1]
root = build_tree([2, 1, 3])
assert tree_to_list(s.invertTree(root)) == [2, 3, 1]
root = build_tree([])
assert tree_to_list(s.invertTree(root)) == []
root = build_tree([1])
assert tree_to_list(s.invertTree(root)) == [1]
root = build_tree([1, 2, None, 3])
assert tree_to_list(s.invertTree(root)) == [1, None, 2, None, 3]
print("all tests passed")
run_tests()| Test | Why |
|---|---|
[4,2,7,1,3,6,9] | Full binary tree |
[2,1,3] | Small normal tree |
[] | Empty tree |
[1] | Single node |
[1,2,None,3] | Skewed tree |