[Medium] 103. Binary Tree Zigzag Level Order Traversal
Given the root of a binary tree, return the zigzag level order traversal of its nodes’ values. (i.e., from left to right, then right to left for the next level and alternate between).
Examples
Example 1:
Input: root = [3,9,20,null,null,15,7]
Output: [[3],[20,9],[15,7]]
Explanation:
Level 0: [3] (left to right)
Level 1: [20,9] (right to left)
Level 2: [15,7] (left to right)
Example 2:
Input: root = [1]
Output: [[1]]
Example 3:
Input: root = []
Output: []
Constraints
- The number of nodes in the tree is in the range
[0, 2000]. -100 <= Node.val <= 100
Thinking Process
- BFS Structure: Maintains level-by-level traversal
- Trees have no cycles — recursion is natural.
- Combine results from left and right subtrees at each node.
- Base case is usually
null; height drives stack space.
Common Approaches
Typical techniques for this pattern:
| Approach | Time | Space | Notes |
|---|---|---|---|
| Queue BFS | O(n) | O(n) | Shortest path in unweighted graphs |
| Multi-source BFS | O(n) | O(n) | Start from all sources simultaneously |
| 0-1 BFS / deque | O(n) | O(n) | Weights 0 or 1 |
| Level-order BFS (this problem) | O(n) | O(w) | Process by depth/layer |
Solution
Solution: BFS with Deque and Direction Toggle
from collections import deque
# 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 zigzagLevelOrder(self, root):
rtn = []
if root is None:
return rtn
queue = deque([root])
leftToRight = True
while queue:
size = len(queue)
level = []
for i in range(size):
curr = queue.popleft()
if leftToRight:
level.append(curr.val)
else:
level.insert(0, curr.val)
if curr.left:
queue.append(curr.left)
if curr.right:
queue.append(curr.right)
rtn.append(level)
leftToRight = not leftToRight
return rtn
Solution Explanation
Approach: Level-order BFS (this problem)
Key idea: 1. BFS Structure: Maintains level-by-level traversal
How the code works:
- BFS Structure: Maintains level-by-level traversal
- Trees have no cycles — recursion is natural.
- Combine results from left and right subtrees at each node.
- Base case is usually
null; height drives stack space.
Walkthrough — input root = [3,9,20,null,null,15,7], expected output [[3],[20,9],[15,7]]:
Level 0: [3] (left to right) Level 1: [20,9] (right to left) Level 2: [15,7] (left to right)
Algorithm Explanation:
- Initialize (Lines 4-6):
- Create empty result vector
- Return empty result if root is null
- Initialize deque with root node
- Set
leftToRight = truefor first level
- Level Processing (Lines 8-25):
- For each level:
- Get current level size (number of nodes at this level)
- Create empty level vector
- Process each node at current level:
- Remove node from front of deque
- Add value based on direction:
- If
leftToRight: append to end of level vector - If
rightToLeft: insert at beginning of level vector
- If
- Add children: Always add left child first, then right child to back of deque
- Add completed level to result
- Toggle direction:
leftToRight = !leftToRight
- For each level:
- Return (Line 26): Return the zigzag level order traversal
Why This Works:
- Deque for BFS:
dequeallows efficient removal from front and insertion at back - Direction Toggle: Alternates between left-to-right and right-to-left
- Insertion Strategy:
- Left-to-right:
push_back()- natural order - Right-to-left:
insert(begin())- reverse order
- Left-to-right:
- Children Order: Always add left then right to maintain level structure
Example Walkthrough:
For root = [3,9,20,null,null,15,7]:
Tree structure:
3
/ \
9 20
/ \
15 7
Level 0 (leftToRight = true):
Process: [3]
Add: level = [3]
Children: [9, 20]
Result: [[3]]
Level 1 (leftToRight = false):
Process: [9, 20]
Add: level.insert(9) → [9], then level.insert(20) → [20, 9]
Children: [15, 7]
Result: [[3], [20, 9]]
Level 2 (leftToRight = true):
Process: [15, 7]
Add: level.push_back(15) → [15], then level.push_back(7) → [15, 7]
Children: []
Result: [[3], [20, 9], [15, 7]]
Complexity Analysis:
- Time Complexity: O(n) where n is the number of nodes
- Each node is visited exactly once
insert()at beginning is O(n) per level, but amortized over all levels is still O(n)
- Space Complexity: O(n) for the result and O(w) for the deque where w is maximum width
- Result stores all n node values
- Deque stores at most one level of nodes (maximum width)
Related Problems
- LC 102: Binary Tree Level Order Traversal - Standard level order
- LC 107: Binary Tree Level Order Traversal II - Reverse level order
- LC 314: Binary Tree Vertical Order Traversal - Vertical traversal
- LC 199: Binary Tree Right Side View - Right side view
Implementation Notes
- Deque vs Queue: Deque allows efficient insertion at both ends
- Insert Performance:
insert(begin())is O(n) per level, but acceptable for this problem - Direction Flag: Simple boolean toggle is cleaner than using level number % 2
- Null Check: Always check for null root before processing
Common Mistakes
- Skipping edge cases (empty input, single element, boundaries).
- Off-by-one errors in loops and index ranges.
- Forgetting to handle the case when no valid answer exists.
Key Takeaways
- BFS Structure: Maintains level-by-level traversal
- Direction Toggle: Simple boolean flag to alternate direction
- Insertion Strategy: Choose insertion method based on direction
- Children Order: Always process left then right to maintain level structure
References
- LC 103: Binary Tree Zigzag Level Order Traversal on LeetCode
- LeetCode Discuss — LC 103: Binary Tree Zigzag Level Order Traversal
- LeetCode Editorial (may require premium)