Pattern 05
DFS + BFS
Traverse trees and graphs. DFS goes deep, BFS goes wide.
When to use
Use for traversal, connectivity, levels, paths, components, and tree recursion. DFS for exploring all paths or doing recursive tree work. BFS for shortest path in unweighted graphs or level-by-level processing.
Core intuition
DFS dives as deep as possible before backtracking — use a stack or recursion. BFS explores all neighbors at the current level before going deeper — use a queue. Both need a visited set for graphs.
Template
# DFS recursive (tree)
def dfs(node):
if not node:
return 0
left = dfs(node.left)
right = dfs(node.right)
return 1 + max(left, right)
# BFS (shortest path / level order)
from collections import deque
def bfs(start):
queue = deque([start])
visited = {start}
steps = 0
while queue:
for _ in range(len(queue)):
node = queue.popleft()
for neighbor in graph[node]:
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
steps += 1
return stepsSuggested problems
Key takeaways
- ›DFS = recursion or explicit stack
- ›BFS = queue, process level by level
- ›Tree problems often want a recursive relation on left/right subtrees
- ›Graph problems almost always need a visited set
- ›Shortest path in unweighted graph → always BFS
You'll see this when...
- ›Tree traversal, depth, height, diameter
- ›Number of islands or connected components
- ›Shortest path between two nodes
- ›Can you reach X from Y?
- ›Level order traversal or BFS layers