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

121 lines
3.1 KiB
Plaintext
Raw Normal View History

---
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