Binary Tree Zigzag Level Order Traversal
Return the tree's values grouped by depth, exactly as in level order, except that the reading direction alternates: the first level (the root) is read left to right, the second right to left, the third left to right again, and so on. The grouping into one list per level is required. An empty tree returns an empty list.
- The number of nodes in the tree is in the range [0, 2000]
- -100 <= Node.val <= 100
- Level 0 (the root) is read left to right
- Direction flips at every level boundary
root = [3,9,20,null,null,15,7][[3],[20,9],[15,7]]root = [1,2,3,4,5,6,7][[1],[3,2],[4,5,6,7]]root = [1,2,null,3][[1],[2],[3]]root = [][]This is Binary Tree Level Order Traversal with one slot filled differently, so the queue loop and the frozen level_size carry over unchanged. What is new is only the order in which a level's values are written down.
The tempting move is to make the traversal itself alternate — enqueue right child before left on flipped levels. It does not work, and understanding why is the useful part. The queue's order determines which nodes are discovered first, and therefore the left-to-right order of the next level as well. Flip the enqueue order and you flip the following level too, then the one after that, and the levels stop corresponding to anything you intended.
So keep the traversal fixed. Nodes always come out of the queue left to right; that is the queue's job and it should be left alone. Only the placement of each value into the current level's list alternates. Two independent things that are easy to conflate: the order of visiting, and the order of recording.
Since level_size is known before the level starts, the level's list can be allocated at full size up front, and each value written straight into its final slot. On a left-to-right level, the i-th node pulled goes to index i. On a right-to-left level, it goes to index level_size - 1 - i — the mirror position, so the first node pulled (leftmost) lands at the far end.
if root is None: return []
out, queue, ltr = [], deque([root]), True
while queue:
n = len(queue) # frozen level size, exactly as before
level = [None] * n # reserve every slot up front
for i in range(n):
node = queue.popleft()
level[i if ltr else n - 1 - i] = node.val # placement flips; traversal does not
if node.left: queue.append(node.left) # ALWAYS left then right
if node.right: queue.append(node.right)
out.append(level)
ltr = not ltr # flip for the next level
return outltr starts as true, because level 0 is read left to right — a parity mistake here is invisible on the root (a single node looks identical in both directions) and only shows up one level down, which makes it annoying to spot.Building each level as a list and reversing the odd ones afterwards is equally valid and equally O(N), since each node participates in at most one reversal. Direct placement simply avoids the second pass.
ltr = true, n = 1. Pull 3, write it at index 0. Level [3]. Enqueue 9 then 20. Flip ltr to false.ltr = false, n = 2. Pull 9 first (i = 0) and write it at index 2 - 1 - 0 = 1. Pull 20 (i = 1) and write it at index 2 - 1 - 1 = 0. Level [20, 9]. Note that 20's children were enqueued in the usual left-then-right order, as 15 then 7. Flip ltr to true.ltr = true, n = 2. Pull 15 into index 0, 7 into index 1. Level [15, 7].Level 1 is the instructive step: 9 was visited first but recorded last. Had we instead enqueued 20's children right-first, level 2 would have come out as [7, 15] before any flipping — the traversal would have been corrupted rather than the presentation.
Unchanged from level order: every node is enqueued once, dequeued once, and written once, so O(N) time and O(W) space for the queue. The alternation is free — one boolean and an index calculation.
The general point is worth keeping: when a problem asks for output in an unusual order, first check whether the traversal has to change at all, or only the presentation. Very often the exploration order is doing something you need and should not be disturbed, and the requirement can be satisfied entirely at the point where results are recorded. The same separation shows up in reverse level order (collect normally, reverse the outer list at the end) and in Binary Tree Left/Right Side View, where the traversal is untouched and only the selection rule changes.
Zigzag Level Order
Alternating Directional BFS
Zigzag flips direction at each level boundary.
"Use a Deque or reverse the level list."
Strategy
Modified BFS: flip collection order using a boolean flag for cada level completion.
"Alternating directional traversal."