Files
leetcode/docs/(algorithms)/breadth-first-search.mdx
T

122 lines
3.1 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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