150NeetCode 150

85.Rotting Oranges

MediumGraphs · 6/19

Problem

You are given an m x n grid where each cell is 0 (empty), 1 (fresh orange) or 2 (rotten orange). Every minute, each fresh orange that is 4-directionally adjacent to a rotten orange becomes rotten.

Return the minimum number of minutes until no fresh orange remains. If some fresh orange can never rot, return -1.

Examples

Input:  grid = [
  [2,1,1],
  [1,1,0],
  [0,1,1]
]
Output: 4
Explanation: The rot spreads from (0,0); the last orange to rot is (2,2), at minute 4.
Input:  grid = [
  [2,1,1],
  [0,1,1],
  [1,0,1]
]
Output: -1
Explanation: The orange at (2,0) is boxed in by the empty cells (1,0) and (2,1), so the rot can never reach it.
Input:  grid = [[0,2]]
Output: 0
Explanation: There are no fresh oranges at minute 0, so no time is needed.

Constraints

  • m == grid.length, n == grid[i].length
  • 1 <= m, n <= 10
  • grid[i][j] is 0, 1 or 2

💡 Key Insight

All rotten oranges spread at the same time, one step per minute. That is exactly a multi-source BFS: put every initially rotten orange in the queue as level 0, and each BFS level is one minute. The time at which a fresh orange is first reached is its shortest distance to any rotten source, and the answer is the number of levels needed to reach the last one. Count fresh oranges up front; if any remain afterwards, return -1.

Brute Force (Minute-by-Minute Simulation)

TimeO((m·n)²)SpaceO(m·n)

Intuition

Literally simulate the clock. Each minute, scan the whole grid and collect every fresh orange that has a rotten neighbour. Rot them all after the scan (so an orange rotted this minute cannot spread in the same minute). Stop when a minute produces no change, then check whether any fresh orange is left.

Algorithm

  1. Repeat:
    • Scan all cells; collect each 1 that has a neighbour equal to 2.
    • If nothing was collected, stop.
    • Set every collected cell to 2 and increment minutes.
  2. If any 1 remains, return -1; else return minutes.

Visualization

minute 0     minute 1     minute 2     minute 3     minute 4
2 1 1        2 2 1        2 2 2        2 2 2        2 2 2
1 1 0        2 1 0        2 2 0        2 2 0        2 2 0
0 1 1        0 1 1        0 1 1        0 2 1        0 2 2

Code

java
import java.util.ArrayList;
import java.util.List;

class Solution {
    private static final int[][] DIRS = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

    public int orangesRotting(int[][] grid) {
        int rows = grid.length, cols = grid[0].length;
        int minutes = 0;

        while (true) {
            // Collect every fresh orange touching a rotten one
            List<int[]> toRot = new ArrayList<>();
            for (int r = 0; r < rows; r++) {
                for (int c = 0; c < cols; c++) {
                    if (grid[r][c] == 1 && hasRottenNeighbour(grid, r, c)) {
                        toRot.add(new int[]{r, c});
                    }
                }
            }
            if (toRot.isEmpty()) break;
            for (int[] cell : toRot) {
                grid[cell[0]][cell[1]] = 2; // apply after the scan
            }
            minutes++;
        }

        for (int[] row : grid) {
            for (int cell : row) {
                if (cell == 1) return -1; // unreachable fresh orange
            }
        }
        return minutes;
    }

    private boolean hasRottenNeighbour(int[][] grid, int r, int c) {
        for (int[] d : DIRS) {
            int nr = r + d[0], nc = c + d[1];
            if (nr >= 0 && nr < grid.length && nc >= 0 && nc < grid[0].length && grid[nr][nc] == 2) {
                return true;
            }
        }
        return false;
    }
}

Complexity

  • Time: O((m·n)²) — there can be up to m·n minutes (a long snake of oranges), each scanning the full grid.
  • Space: O(m·n) — the toRot list.

Complexity Comparison

Approach Time Space
Brute Force Simulation O((m·n)²) O(m·n)
BFS from Each Rotten Orange O(k·m·n) O(m·n)
Multi-Source BFS O(m·n) O(m·n)

Common Pitfalls

  • Looping while (!queue.isEmpty()) without the fresh > 0 guard and incrementing minutes after the last level — this over-counts by one, because the final level rots nothing.
  • Returning -1 when there are no fresh oranges at all; the correct answer is 0 (e.g. [[0,2]] or [[0]]).
  • Rotting oranges during the scan in the simulation, which lets rot travel several cells in a single minute.
  • Running separate BFS passes and taking the max instead of the min distance per cell.
  • Forgetting to check for unreachable fresh oranges at the end.