150NeetCode 150

53.Binary Tree Level Order Traversal

MediumBlind 75Trees Ā· 8/15

Problem

Given the root of a binary tree, return the level order traversal of its node values: a list of levels, from top to bottom, where each level lists its values from left to right.

Examples

Input:  root = [3,9,20,null,null,15,7]
Output: [[3],[9,20],[15,7]]
Input:  root = [1]
Output: [[1]]
Input:  root = []
Output: []

Constraints

  • The number of nodes in the tree is in the range [0, 2000].
  • -1000 <= Node.val <= 1000

šŸ’” Key Insight

A FIFO queue naturally visits nodes in level order: everything on level d is enqueued before anything on level d + 1. By snapshotting the queue size at the start of each round, we know exactly how many nodes belong to the current level and can group them into one list.

Brute Force (Collect One Level at a Time)

TimeO(n Ā· h)SpaceO(h)

Intuition

Compute the tree height H. Then, for each level d from 0 to H - 1, run a fresh DFS from the root that only records nodes at depth d. Pre-order visits left before right, so values on each level come out in left-to-right order.

Algorithm

  1. H = height(root).
  2. For d in 0 .. H - 1:
    • Create an empty list, run collect(root, d, list), append the list.
  3. collect(node, d, list): if node is null return; if d == 0 add node.val; else recurse on both children with d - 1.

Visualization

H = 3
d = 0: DFS stops at depth 0          -> [3]
d = 1: DFS goes 1 deep               -> [9, 20]
d = 2: DFS goes 2 deep               -> [15, 7]
Nodes near the top are re-visited on every pass.

Code

java
import java.util.ArrayList;
import java.util.List;

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        int height = height(root);
        for (int d = 0; d < height; d++) {
            List<Integer> level = new ArrayList<>();
            collect(root, d, level);
            result.add(level);
        }
        return result;
    }

    private int height(TreeNode node) {
        if (node == null) return 0;
        return 1 + Math.max(height(node.left), height(node.right));
    }

    // add every node exactly `depth` levels below `node`, left to right
    private void collect(TreeNode node, int depth, List<Integer> level) {
        if (node == null) return;
        if (depth == 0) {
            level.add(node.val);
            return;
        }
        collect(node.left, depth - 1, level);
        collect(node.right, depth - 1, level);
    }
}

Complexity

  • Time: O(n Ā· h) — each of the h passes may touch every node above its target depth; O(n²) for a skewed tree.
  • Space: O(h) — recursion depth (excluding the output).

Complexity Comparison

Approach Time Space
Brute Force (Collect One Level at a Time) O(n Ā· h) O(h)
DFS with Depth Index O(n) O(h)
BFS with a Queue O(n) O(w)

Common Pitfalls

  • Using queue.size() directly as the for loop bound — it grows while children are enqueued, so levels bleed into each other. Snapshot it first.
  • Returning [[]] for an empty tree instead of [].
  • Enqueuing null children into an ArrayDeque, which throws NullPointerException; check before offering.
  • In the DFS version, visiting right before left reverses each level's order.