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).
Example 1:
Input: root = [3,9,20,null,null,15,7] Output: [[3],[9,20],[15,7]]
Example 2:
Input: root = [1] Output: [[1]]
Example 3:
Input: root = [] Output: []
Constraints:
[0, 2000]
.-1000 <= Node.val <= 1000
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
We want to visit all nodes of the tree level by level. The brute force method is like exploring every single possible path to each level of the tree, without any particular strategy.
Here's how the algorithm would work step-by-step:
def level_order_brute_force(root):
def get_tree_height(node):
if not node:
return 0
left_height = get_tree_height(node.left)
right_height = get_tree_height(node.right)
return max(left_height, right_height) + 1
def get_nodes_at_level(node, level, current_level, level_nodes):
if not node:
return
# If we've reached the target level, append the node's value.
if current_level == level:
level_nodes.append(node.val)
return
get_nodes_at_level(node.left, level, current_level + 1, level_nodes)
get_nodes_at_level(node.right, level, current_level + 1, level_nodes)
if not root:
return []
tree_height = get_tree_height(root)
result = []
# Iterate through each level of the tree.
for level in range(1, tree_height + 1):
level_nodes_list = []
#For each level, retrieve the nodes at each level
get_nodes_at_level(root, level, 1, level_nodes_list)
result.append(level_nodes_list)
return result
The task is to visit every level of the tree and collect the nodes at each level in order. We will accomplish this by processing the tree level by level, making sure we visit all nodes at a particular level before going deeper. The key is to remember which node belongs to which level.
Here's how the algorithm would work step-by-step:
from collections import deque
def levelOrder(root):
if not root:
return []
result = []
nodes_queue = deque([root])
# Iterate while there are nodes to process
while nodes_queue:
level_size = len(nodes_queue)
current_level = []
# Process all nodes at the current level
for _ in range(level_size):
node = nodes_queue.popleft()
current_level.append(node.val)
# Add the left child if it exists
if node.left:
nodes_queue.append(node.left)
# Add the right child if it exists
if node.right:
nodes_queue.append(node.right)
result.append(current_level)
return result
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def level_order_traversal(root):
if not root:
return []
results = []
queue_of_nodes = deque([root])
# Continue as long as nodes exist on the queue
while queue_of_nodes:
level_length = len(queue_of_nodes)
current_level_nodes = []
# Process nodes on current level
for _ in range(level_length):
node_being_processed = queue_of_nodes.popleft()
current_level_nodes.append(node_being_processed.val)
# Left child is enqueued next
if node_being_processed.left:
queue_of_nodes.append(node_being_processed.left)
# Right child is enqueued last
if node_being_processed.right:
queue_of_nodes.append(node_being_processed.right)
results.append(current_level_nodes)
return results
Case | How to Handle |
---|---|
Null or empty root node | Return an empty list immediately since there is nothing to traverse. |
Single node tree (only root) | Return a list containing a single list with the root's value. |
Completely skewed tree (all nodes on one side) | The queue will grow linearly with the number of nodes, and the algorithm should still process all levels correctly, though space complexity might be a concern for very large trees. |
Perfectly balanced tree | The algorithm should handle balanced trees efficiently, and space complexity will be logarithmic with respect to the number of nodes. |
Tree with duplicate node values | Duplicate node values don't affect the level order traversal logic as it focuses on the structure of the tree, not the values themselves. |
Large tree (approaching memory limits) | Be mindful of memory usage as the queue grows with the width of the tree, potentially causing memory exhaustion for very large trees; iterative solutions are typically better in Python to avoid recursion limits. |
Tree with negative and positive values | The algorithm works correctly with both positive and negative values, as it is agnostic to the value range. |
Tree with a wide shallow structure compared to a deep narrow structure. | The algorithm should correctly traverse both, but the space complexity using BFS is dependent on the width of the tree. |