226. Invert Binary Tree - Explanation
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.
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
1. Breadth First Search
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
- If the tree is empty, return
null. - Initialize a queue and insert the
rootnode. - While the queue is not empty:
- Remove the front node.
- Swap its
leftandrightchildren. - If the
leftchild exists, add it to the queue. - If the
rightchild exists, add it to the queue.
- After all nodes are processed, return the
rootas the inverted tree.
# 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 rootTime & Space Complexity
- Time complexity:
- Space complexity:
2. Depth First Search
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
- If the current node is
null, returnnull. - Swap the node's
leftandrightpointers. - Recursively call
dfson the newleftchild. - Recursively call
dfson the newrightchild. - Return the current node (now inverted).
# 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 rootTime & Space Complexity
- Time complexity:
- Space complexity: 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:
- Push the root into the stack.
- Pop the top node, swap its children.
- Push its children onto the stack (if they exist).
- 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
- If
rootisnull, returnnull. - Initialize a stack with
root. - While stack is not empty:
- Pop a node.
- Swap its
leftandrightpointers. - If the
leftchild exists, push it to the stack. - If the
rightchild exists, push it to the stack.
- Return the
root.
# 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 rootTime & Space Complexity
- Time complexity:
- Space complexity:
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.
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.
Sign in to join the discussion