Rotting Oranges (LC 994)
On this page
Pattern: Multi-Source BFS (Simultaneous Spread) Difficulty: Medium Key Concept: All initially rotten oranges spread their rot at the same time. Push every rotten cell into the BFS queue at once, then do level-order BFS — each level = 1 minute.
Problem Statement
A 2-D grid of values:
0= empty1= fresh orange2= rotten orange
Each minute, any fresh orange adjacent (4-directionally) to a rotten one becomes rotten. Return the minimum minutes until no fresh orange remains, or -1 if some fresh orange is unreachable.
Example
grid = [[2,1,1],[1,1,0],[0,1,1]]→4grid = [[2,1,1],[0,1,1],[1,0,1]]→-1grid = [[0,2]]→0
1. Algorithm & Pseudocode
queue = all initial rotten cells
fresh = count of 1s
if fresh == 0: return 0
minutes = 0
while queue not empty AND fresh > 0:
size = queue.size()
for i in 0..size-1:
(r, c) = queue.poll()
for each 4-direction neighbor (nr, nc):
if in bounds and grid[nr][nc] == 1:
grid[nr][nc] = 2
fresh--
queue.offer((nr, nc))
minutes++
return fresh == 0 ? minutes : -1
2. Step-by-Step Analysis
Why multi-source BFS
The spread is simultaneous — every existing rotten orange contaminates a neighbor in the same minute. By pushing all initial rotten cells before starting BFS, level k of the BFS = time k after start.
Why count fresh
If after BFS some fresh oranges remain (unreachable from any rotten source), return -1. Saves a final grid scan.
Why size = queue.size() outer loop
We must process all cells reached at this minute before incrementing time.
Edge case — no fresh oranges initially: return 0.
ASCII Trace for [[2,1,1],[1,1,0],[0,1,1]]
initial rotten: {(0,0)} fresh = 6
minute 1: spread to (0,1),(1,0) fresh = 4
minute 2: spread to (0,2),(1,1) fresh = 2
minute 3: spread to (2,1) fresh = 1
minute 4: spread to (2,2) fresh = 0
return 4
3. Java Solution
class Solution {
private static final int[][] DIRS = {{0,1},{1,0},{0,-1},{-1,0}};
public int orangesRotting(int[][] grid) {
int m = grid.length, n = grid[0].length, fresh = 0;
Queue<int[]> q = new ArrayDeque<>();
for (int r = 0; r < m; r++)
for (int c = 0; c < n; c++) {
if (grid[r][c] == 1) fresh++;
else if (grid[r][c] == 2) q.offer(new int[]{r, c});
}
if (fresh == 0) return 0;
int minutes = 0;
while (!q.isEmpty() && fresh > 0) {
int size = q.size();
for (int i = 0; i < size; i++) {
int[] cur = q.poll();
for (int[] d : DIRS) {
int nr = cur[0] + d[0], nc = cur[1] + d[1];
if (nr >= 0 && nc >= 0 && nr < m && nc < n && grid[nr][nc] == 1) {
grid[nr][nc] = 2;
fresh--;
q.offer(new int[]{nr, nc});
}
}
}
minutes++;
}
return fresh == 0 ? minutes : -1;
}
}
Time: (O(m \cdot n)) Space: (O(m \cdot n)) for the queue worst case
4. The “Java vs. Others” Edge
static final int[][] DIRS = {...}is the cleanest way to encode 4-neighbors in Java.- We mutate the grid in place (set to 2) — saves a
boolean[][] visited. - The pattern of “push all sources, then BFS by level” appears in many problems: walls and gates (LC 286), 01 matrix (LC 542), shortest bridge (LC 934).
5. Complexity Summary
| Approach | Time | Space | Notes |
|---|---|---|---|
| Multi-BFS | O(m·n) | O(m·n) | Cleanest; preserves true min |
| DFS | infeasible | — | Can’t model simultaneous spread |