Problem
Given a binary tree, find the maximum width among all of its levels. The width of a level is the number of positions between the leftmost and rightmost nodes, counting every null slot in between as if it were filled. Only the outermost non-null nodes determine the endpoints β interior nulls count toward the width but a trailing null at the right end does not extend it.
[1,3,2,5,3,null,9]
- Input: root = [1, 3, 2, 5, 3, null, 9]
- Output: 4
- Explanation: The bottom level spans positions 0 through 3 β nodes 5, 3, a null gap, and 9 β giving a width of 4.
Intuition
Think of a complete binary tree where every node at index i has a left child at 2i and a right child at 2i + 1. Even in a sparse tree, we can label each node with the index it would hold in that imagined complete tree. The width of any level is simply rightmost_index - leftmost_index + 1. BFS lets us process one level at a time, so we just need to track how spread apart the leftmost and rightmost indices are on each pass.
The subtle issue is that these indices double with every level β a tree of depth 30 would produce indices larger than 2Β³β°. The fix is to normalize: subtract the leftmost index from every node's position at the start of each level. The relative gaps are preserved, and the numbers stay small.
Solution β BFS with Position Indexing
Process the tree level by level with BFS. Carry each node's imagined complete-tree index through the queue. At the start of each level, normalize all indices by subtracting the first position so they never grow large. The width of the level is last_normalized_index + 1 (since the normalized leftmost is always 0).
- Enqueue the root with position 0.
- For each level, note the position of the very first node β this is the normalization offset.
- Process each node: subtract the offset to get its normalized position, then enqueue its children at
2 * normalized_posand2 * normalized_pos + 1. - After finishing the level, the last normalized position seen equals
width - 1. - Update the running maximum and repeat.
1from collections import deque
2
3def widthOfBinaryTree(root):
4 if not root:
5 return 0
6
7 max_width = 0
8 queue = deque([(root, 0)]) # (node, position in imagined complete tree)
9
10 while queue:
11 level_size = len(queue)
12 level_offset = queue[0][1] # leftmost position β subtract this to normalize
13 last_normalized = 0
14
15 for _ in range(level_size):
16 node, pos = queue.popleft()
17 normalized_pos = pos - level_offset # keep indices from overflowing
18 last_normalized = normalized_pos
19
20 if node.left:
21 queue.append((node.left, 2 * normalized_pos))
22 if node.right:
23 queue.append((node.right, 2 * normalized_pos + 1))
24
25 max_width = max(max_width, last_normalized + 1) # +1 because both ends are inclusive
26
27 return max_widthTime: O(n) β every node is visited exactly once during BFS.
Space: O(n) β the queue holds at most all nodes on the widest level, which can be up to n/2 nodes in a complete binary tree.
Complexity Summary
| Approach | Time | Space | When to use |
|---|---|---|---|
| BFS with position indexing | O(n) | O(n) | Any binary tree width problem where level-by-level processing is natural |
Common Mistakes
- Using
intfor positions instead oflongβ indices double at each level, so a tree 32 levels deep would overflow a 32-bit integer even before normalization. Always uselong(Java) orlong long(C++). - Skipping normalization β even with 64-bit integers, a tree of depth 64 would produce positions exceeding 2βΆΒ³. Subtracting the leftmost position at the start of each level resets the range to zero-based and prevents overflow.
- Computing width as
last - firstinstead oflast - first + 1β both the leftmost and rightmost nodes are included, so the span needs the extra 1. A single-node level has width 1, not 0. - Filling the queue with null placeholders β a common brute-force idea is to insert null sentinels for every absent child so you can count total slots per level. This blows up to O(2^depth) queue size and will time out on deep unbalanced trees.
- Confusing null gaps with trailing nulls β a null between two non-null nodes counts toward the width, but nulls past the rightmost non-null node do not. The position-index approach handles this automatically since you only look at the first and last non-null node positions.
Related Problems
binary-tree-level-order-traversalβ foundational BFS-per-level pattern this solution builds onbinary-tree-right-side-viewβ also picks a single representative node per level using BFSbinary-tree-zigzag-level-order-traversalβ level-by-level BFS with a direction toggle per depthmaximum-depth-of-binary-treeβ counts levels rather than measuring span, same BFS framingmaximum-level-sum-of-a-binary-treeβ aggregates values per level with the same BFS template