title: Binary Tree Level Order Traversal
slug: binary-tree-level-order
difficulty: medium
leetcode_id: 102
leetcode_url: https://leetcode.com/problems/binary-tree-level-order-traversal/
categories:
  - trees
  - queue
patterns:
  - bfs

description: |
  Given the `root` of a binary tree, return the level order traversal of its nodes' values
  (i.e., from left to right, level by level).

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

examples:
  - input: "root = [3,9,20,null,null,15,7]"
    output: "[[3],[9,20],[15,7]]"
    explanation: "Level 0 has 3, level 1 has 9 and 20, level 2 has 15 and 7."
  - input: "root = [1]"
    output: "[[1]]"
    explanation: "Single node at level 0."
  - input: "root = []"
    output: "[]"
    explanation: "Empty tree returns empty list."

explanation:
  approach: |
    1. Use a queue for BFS traversal
    2. Track the number of nodes at current level
    3. Process all nodes at current level before moving to next
    4. Add children to queue as we process each node
    5. Collect values for each level in a separate list

  intuition: |
    BFS naturally visits nodes level by level. By tracking how many nodes are in the queue
    at the start of each level, we know exactly when one level ends and the next begins.

    The key insight is that after processing all nodes of level k, the queue contains
    exactly all nodes of level k+1.

  common_pitfalls:
    - title: Not tracking level boundaries
      description: |
        Without tracking level size, you can't separate nodes into their levels.
        Capture queue size at the start of each level iteration.
      wrong_approach: "Processing queue without counting level size"
      correct_approach: "level_size = len(queue); process level_size nodes"

    - title: Forgetting null check
      description: |
        Empty tree (null root) should return empty list, not cause an error.

    - title: Using list as queue
      description: |
        Using list.pop(0) is O(n). Use collections.deque for O(1) popleft.

  key_takeaways:
    - BFS with queue is the standard for level-order traversal
    - Track level size to group nodes by level
    - This pattern extends to many tree problems (zigzag, right side view, etc.)
    - deque is more efficient than list for queue operations

  time_complexity: "O(n)"
  space_complexity: "O(n)"
  complexity_explanation: |
    Time: Visit each node exactly once.
    Space: Queue holds at most one level of nodes, which is O(n) in worst case (complete tree).

solutions:
  - approach_name: BFS with Queue (Optimal)
    is_optimal: true
    code: |
      from collections import deque

      class TreeNode:
          def __init__(self, val=0, left=None, right=None):
              self.val = val
              self.left = left
              self.right = right

      def level_order(root: TreeNode | None) -> list[list[int]]:
          if not root:
              return []

          result = []
          queue = deque([root])

          while queue:
              level_size = len(queue)
              level_values = []

              for _ in range(level_size):
                  node = queue.popleft()
                  level_values.append(node.val)

                  if node.left:
                      queue.append(node.left)
                  if node.right:
                      queue.append(node.right)

              result.append(level_values)

          return result
    explanation: |
      Process nodes level by level using a queue.
      Track level size to know when to start a new level list.

  - approach_name: DFS with Level Tracking
    is_optimal: false
    code: |
      def level_order(root: TreeNode | None) -> list[list[int]]:
          result = []

          def dfs(node: TreeNode | None, level: int) -> None:
              if not node:
                  return

              if level == len(result):
                  result.append([])

              result[level].append(node.val)

              dfs(node.left, level + 1)
              dfs(node.right, level + 1)

          dfs(root, 0)
          return result
    explanation: |
      DFS alternative: pass level as parameter and append to appropriate list.
      Same time complexity but uses recursion stack space.
