Rotting Oranges
Picture
A fresh orange lies between two rotten oranges. Both ends start at minute zero, so the middle rots at minute one. Put all starting oranges into the queue together; one distance wave grows from all of them.
Predict
What prevents a fresh orange reached from two directions from being counted twice?
Walk through the small example
Mark it as discovered when enqueuing it, not when removing it later. It then enters exactly once.
Mental model and complete Python solution
The initial queue is the complete time-zero layer. Removing a state at minute t offers its fresh neighbors time t+1. Because all edges take one minute, no later offer can arrive earlier. Record how many fresh oranges remain and the latest discovery time. Empty cells are not traversable, so disconnected fresh cells may never receive an offer.
What the function promises: A rectangular grid uses 0 for empty, 1 for fresh, 2 for rotten. Return elapsed minutes, zero when already done, or −1 if some fresh orange cannot rot. The input is not changed.
from collections import deque
def rotting_time(grid):
if not grid or not grid[0]:
return 0
rows, cols = len(grid), len(grid[0])
queue, seen = deque(), set()
fresh = 0
for r in range(rows):
for c in range(cols):
if grid[r][c] == 2:
queue.append((r, c, 0))
seen.add((r, c))
elif grid[r][c] == 1:
fresh += 1
elapsed = 0
while queue:
r, c, minute = queue.popleft()
for nr, nc in ((r-1,c), (r+1,c), (r,c-1), (r,c+1)):
if (0 <= nr < rows and 0 <= nc < cols
and grid[nr][nc] == 1 and (nr, nc) not in seen):
seen.add((nr, nc))
fresh -= 1
elapsed = minute + 1
queue.append((nr, nc, elapsed))
return elapsed if fresh == 0 else -1
assert rotting_time([[2, 1, 2]]) == 1
assert rotting_time([[2, 0, 1]]) == -1
assert rotting_time([[0, 2]]) == 0
Work and storage: O(RC) time and space: each cell is scanned once and each fresh cell is enqueued at most once.
When to recognize it: Several starting places act at time zero. Put all of them in the queue before processing the first layer.
Check before applying it: A fresh orange may be unreachable. Different spreading times would require a weighted shortest-path method.
Change one rule
We ask for distance to the nearest zero in a binary matrix. What changes?
See what changes
Seed every zero at distance zero, traverse all cells, and store the first distance for each cell. This is the same multi-source BFS, with different sources and traversability rules.
Connect
bfs: The queue still represents increasing distance layers.
Shortest Path Visiting All Nodes: Try every possible starting vertex in one BFS.
Problem reference: Rotting Oranges (Medium). The walkthrough and Python solution above are original course material.