--- title: Breadth-First Search --- # Breadth-First Search (BFS) ## The idea You want a mango seller. You ask your friends first. No luck? You ask friends-of-friends. Then their friends. You search in **rings**, closest first. That is BFS. It answers two questions: 1. **Is there a path** from A to B? 2. **What is the shortest path?** (unweighted — fewest hops) BFS is *always* shortest path on unweighted graphs. First time you reach a node = fewest possible steps. ## The picture ```mermaid flowchart TD YOU((You)) --> A((Alice)) YOU --> B((Bob)) A --> C((Claire)) A --> D((Dan)) B --> E((Eve)) E --> M((Mango seller ✓)) style YOU fill:#1565c0,color:#fff style A fill:#6a1b9a,color:#fff style B fill:#6a1b9a,color:#fff style C fill:#ef6c00,color:#fff style D fill:#ef6c00,color:#fff style E fill:#ef6c00,color:#fff style M fill:#2e7d32,color:#fff ``` Blue = start. Purple = ring 1. Orange = ring 2. Green = found at ring 3. ## The two tools 1. **Queue** — first in, first out. This keeps the rings in order. 2. **Visited set** — never check the same node twice. Without it, cycles loop forever. ## The template ```python from collections import deque def bfs(start, graph: dict) -> None: queue = deque([start]) visited = {start} while queue: level_size = len(queue) # snapshot = one full ring for _ in range(level_size): node = queue.popleft() # process node here for nxt in graph.get(node, []): if nxt not in visited: visited.add(nxt) # mark WHEN queued, not when popped queue.append(nxt) ``` ## Multi-source BFS (LC 994 — Rotting Oranges) Start with *all* rotten oranges in the queue at once. Each ring = one minute of rot spreading. ```python from collections import deque def oranges_rotting(grid: list[list[int]]) -> int: rows, cols = len(grid), len(grid[0]) queue = deque() fresh = 0 for r in range(rows): for c in range(cols): if grid[r][c] == 2: queue.append((r, c)) elif grid[r][c] == 1: fresh += 1 minutes = 0 dirs = [(1, 0), (-1, 0), (0, 1), (0, -1)] while queue and fresh > 0: for _ in range(len(queue)): r, c = queue.popleft() for dr, dc in dirs: nr, nc = r + dr, c + dc if 0 <= nr < rows and 0 <= nc < cols and grid[nr][nc] == 1: grid[nr][nc] = 2 fresh -= 1 queue.append((nr, nc)) minutes += 1 return minutes if fresh == 0 else -1 ``` ## Complexity | | Time | Space | |---|---|---| | BFS | O(V + E) | O(V) | V = nodes, E = edges. On a grid: O(rows × cols). ## Close-out ritual Before you submit, say out loud: 1. Time and space complexity. 2. One edge case trace: empty graph, start = target, or unreachable target. ## Plan problems **Tree BFS A-set:** LC 102 · 199 · 1448 **Graph BFS A-set:** LC 994 · 127 **B-set:** LC 103 · 637 · 909 · 433 · 286