Binary Tree Zigzag Level Order Traversal

MediumTrees · BFS (Level Order)🧩 Tree BFS (Level Order)LeetCode #103 ↗Updated

Problem

Given the root of a binary tree, return its values grouped level by level, but alternate the reading direction: the root level is read left to right, the next right to left, the one after left to right again, and so on.
Input[3,9,20,null,null,15,7]Output[[3],[20,9],[15,7]]
Input[1]Output[[1]]
Input[]Output[]

0 ≤ nodes ≤ 2000  ·  -100 ≤ Node.val ≤ 100

Try it yourself

Java
class Solution {
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
Zigzag changes where a value is written, not the order nodes are visited. Do a normal left-to-right BFS and, on odd levels, place the i-th polled value at slot size - 1 - i.
PatternTree BFS (Level Order)

Instinct The answer talks about levels, rows, depth order, "closest to the root" or what you see from a side? Queue the tree and process it one level at a time.

Memory hack Freeze the size, drain the row - read n = queue.size() before the loop and one level never bleeds into the next.

Open the Tree BFS (Level Order) guide →

Approaches

Brute ForceHeight + DFS per Level, then Reverse

Time O(n · h)Space O(h)

Find the height h. For each depth d run a fresh DFS that collects only the nodes exactly d edges down (left before right), then reverse that list when d is odd. Upper levels get re-walked for every deeper level.

Java
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
    List<List<Integer>> res = new ArrayList<>();
    int h = height(root);
    for (int d = 0; d < h; d++) {
        List<Integer> level = new ArrayList<>();
        collect(root, d, level);
        if (d % 2 == 1) Collections.reverse(level);
        res.add(level);
    }
    return res;
}
private int height(TreeNode node) {
    return node == null ? 0 : 1 + Math.max(height(node.left), height(node.right));
}
private void collect(TreeNode node, int d, List<Integer> level) {
    if (node == null) return;
    if (d == 0) {
        level.add(node.val);
        return;
    }
    collect(node.left, d - 1, level);
    collect(node.right, d - 1, level);
}

Easy to get right, but a skewed tree (h = n) makes it quadratic.

At a glance

LevelApproachTimeSpace
Brute ForceHeight + DFS per Level, then ReverseO(n · h)O(h)
BetterBFS, then Reverse Odd LevelsO(n)O(w)
OptimalBFS with Direct Slot PlacementO(n)O(w)
Common pitfalls
  • Swapping the left/right enqueue order on odd levels — breaks the order of the level after.
  • Using queue.size() as the loop bound while children are being added.
  • Forgetting the empty tree → NPE on the first poll().
Interview tips
  • Say up front: “this is level order with a direction flag”.
  • Offer the reverse-each-odd-level version first, then remove the extra pass.
  • Mention the two-stack or deque (addFirst/addLast) variants as alternatives.
Pattern
BFS level-by-level + per-level transform → any traversal where each depth is emitted as a group with its own rule.
My notes saved in this browser