Binary Tree Level Order Traversal
MediumGiven the root of a binary tree, return the level order traversal of its nodes' values. (i.e., from left to right, level by level).
Example
Input: root = [3,9,20,null,null,15,7]
Output: [[3],[9,20],[15,7]]
Explanation
The most efficient approach to solve this problem is using Breadth-First Search (BFS) with a queue. The key insight is that BFS naturally visits nodes level by level, and we can use the queue size to track each level's boundary.
We process the tree level by level using the following steps:
- Initialize a
queuewith the root node - While the queue is not empty, get the current
level_size(number of nodes at this level) - Process all nodes at the current level by dequeuing
level_sizenodes - For each node, add its children to the queue for the next level
This approach works because by capturing the queue size at the start of each level, we know exactly how many nodes belong to the current level before any next-level nodes are added.
Idea Map
Initialize queue = deque([root])
While queue is not empty
1. level_size = len(queue)
2. For i in range(level_size):
Dequeue node, add to level[]
Enqueue node.left, node.right
3. Append level to result
Complexity Analysis
Time Complexity
O(n) - We visit every node in the tree exactly once.
Space Complexity
O(n) - The queue holds at most n/2 nodes (the widest level of the tree).
Code
def levelOrder(root):
Defines the function `levelOrder` which takes the `root` of a binary tree as input and returns the level order traversal.
if not root:
Base case: if the tree is empty (root is None), there are no nodes to traverse.
return []
Return an empty list immediately for an empty tree.
result = []
Initialize the result list that will hold sub-lists for each level.
queue = deque([root])
Create a deque (double-ended queue) initialized with the root node to start BFS.
while queue:
Continue processing while there are still nodes in the queue (levels left to visit).
level_size = len(queue)
Capture the number of nodes at the current level before processing. This is the key to separating levels.
level = []
Create a temporary list to store values of all nodes at the current level.
for _ in range(level_size):
Loop exactly `level_size` times to process only nodes belonging to the current level.
node = queue.popleft()
Dequeue the front node from the queue (FIFO order ensures left-to-right processing).
level.append(node.val)
Add the current node's value to the current level list.
if node.left:
Check if the current node has a left child before enqueuing it.
queue.append(node.left)
Add the left child to the queue so it will be processed in the next level.
if node.right:
Check if the current node has a right child before enqueuing it.
queue.append(node.right)
Add the right child to the queue so it will be processed in the next level.
result.append(level)
After processing all nodes at this level, add the level list to the result.
return result
Return the complete level order traversal as a list of lists.
public List<List<Integer>> levelOrder(TreeNode root) {
Defines the method that takes a TreeNode root and returns a list of lists containing integer values for each level.
List<List<Integer>> result = new ArrayList<>();
Initialize the result list that will hold sub-lists for each level of the tree.
if (root == null) return result;
Base case: if the tree is empty, return the empty result list immediately.
Queue<TreeNode> queue = new LinkedList<>();
Create a LinkedList-based Queue to perform BFS traversal.
queue.offer(root);
Add the root node to the queue to begin the BFS traversal.
while (!queue.isEmpty()) {
Continue processing while there are nodes in the queue (levels left to visit).
int levelSize = queue.size();
Capture the number of nodes at the current level. This is essential for separating levels.
List<Integer> level = new ArrayList<>();
Create a temporary list to collect values of all nodes at the current level.
for (int i = 0; i < levelSize; i++) {
Loop exactly `levelSize` times to process only nodes belonging to the current level.
TreeNode node = queue.poll();
Dequeue the front node from the queue (FIFO order ensures left-to-right processing).
level.add(node.val);
Add the current node's value to the current level list.
if (node.left != null) queue.offer(node.left);
If the left child exists, add it to the queue for processing in the next level.
if (node.right != null) queue.offer(node.right);
If the right child exists, add it to the queue for processing in the next level.
}
End of the for loop that processes all nodes at the current level.
result.add(level);
After processing all nodes at this level, add the level list to the result.
}
End of the while loop.
return result;
Return the complete level order traversal as a list of lists.
}
End of the method.
vector<vector<int>> levelOrder(TreeNode* root) {
Defines the function that takes a pointer to the root TreeNode and returns a 2D vector of integers.
vector<vector<int>> result;
Initialize the result 2D vector that will hold vectors for each level of the tree.
if (!root) return result;
Base case: if the tree is empty (null pointer), return the empty result immediately.
queue<TreeNode*> q;
Create a queue of TreeNode pointers to perform BFS traversal.
q.push(root);
Push the root node onto the queue to begin the BFS traversal.
while (!q.empty()) {
Continue processing while there are nodes in the queue (levels left to visit).
int levelSize = q.size();
Capture the number of nodes at the current level. This is essential for separating levels.
vector<int> level;
Create a temporary vector to collect values of all nodes at the current level.
for (int i = 0; i < levelSize; i++) {
Loop exactly `levelSize` times to process only nodes belonging to the current level.
TreeNode* node = q.front();
Get a pointer to the front node of the queue (peek without removing).
q.pop();
Remove the front node from the queue (in C++, front() and pop() are separate operations).
level.push_back(node->val);
Add the current node's value to the current level vector.
if (node->left) q.push(node->left);
If the left child exists, push it onto the queue for processing in the next level.
if (node->right) q.push(node->right);
If the right child exists, push it onto the queue for processing in the next level.
}
End of the for loop that processes all nodes at the current level.
result.push_back(level);
After processing all nodes at this level, add the level vector to the result.
}
End of the while loop.
return result;
Return the complete level order traversal as a 2D vector.
}
End of the function.
Edge Cases & Common Mistakes
Forgetting to track level boundaries
Without level_size = len(queue), you'll process all nodes as one level instead of separating them. Always capture the queue size before processing each level.
Empty tree (null root)
Always check for null root before starting BFS to avoid runtime errors. An empty tree should return an empty list.
Single node tree
Returns [[root.val]] correctly with no special handling needed. The loop processes the single node and terminates since it has no children.
Related Problems
What is Breadth-First Search (BFS)?
BFS is a graph traversal algorithm that explores all vertices at the present depth before moving to vertices at the next depth level. It uses a queue data structure to track which vertex to visit next, ensuring that closer nodes are always visited before farther ones.
Learn more about BFS →Disclaimer: This problem is for educational purposes. Practice the 'Binary Tree Level Order Traversal' problem on LeetCode.