← Back to DSA
#994

Rotting Oranges

Rotting Oranges solution for LeetCode 994, with the key idea, complexity breakdown, and working code in Java, C++, JavaScript, TypeScript, C, Go, and Rust.

Medium
ArrayBreadth-First SearchMatrix
Solve on LeetCode ↗

Rotting Oranges

What the problem is really asking

Every rotten orange spreads rot to its four neighbors in one minute.

So the question is really asking:

"If all rotten oranges start spreading at the same time, how many minutes does it take to reach every fresh orange?"

Intuition

This is not a single-source BFS.

All rotten oranges are active at minute 0, which means they should all go into the queue at the beginning.

That is exactly what multi-source BFS does.

Brute-force idea

A slow way would be:

  • simulate minute 1 by scanning the whole grid
  • then scan again for minute 2
  • then again for minute 3

That works, but it repeats a lot of unnecessary work because we keep revisiting the full matrix.

Optimized approach

We do one initial pass:

  • push every rotten orange into the queue
  • count how many fresh oranges exist

Then BFS spreads outward level by level:

  • one BFS layer = one minute
  • whenever a fresh orange becomes rotten, decrease fresh
  • when fresh becomes 0, we know all oranges are covered

If BFS ends and fresh is still positive, some orange was unreachable, so the answer is -1.

Code Solution

Switch between languages

import java.util.ArrayDeque;
import java.util.Queue;

class Solution {
    public int orangesRotting(int[][] grid) {
        int rows = grid.length;
        int cols = grid[0].length;
        Queue<int[]> queue = new ArrayDeque<>();
        int fresh = 0;
        int minutes = 0;

        for (int row = 0; row < rows; row++) {
            for (int col = 0; col < cols; col++) {
                if (grid[row][col] == 2) {
                    queue.offer(new int[] {row, col});
                } else if (grid[row][col] == 1) {
                    fresh++;
                }
            }
        }

        int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

        while (!queue.isEmpty() && fresh > 0) {
            int size = queue.size();
            minutes++;

            for (int i = 0; i < size; i++) {
                int[] current = queue.poll();

                for (int[] direction : directions) {
                    int nextRow = current[0] + direction[0];
                    int nextCol = current[1] + direction[1];

                    if (
                        nextRow < 0 || nextCol < 0 || nextRow == rows || nextCol == cols
                        || grid[nextRow][nextCol] != 1
                    ) {
                        continue;
                    }

                    grid[nextRow][nextCol] = 2;
                    fresh--;
                    queue.offer(new int[] {nextRow, nextCol});
                }
            }
        }

        return fresh == 0 ? minutes : -1;
    }
}

Dry run

For

[
  [2, 1, 1],
  [1, 1, 0],
  [0, 1, 1]
]
  • minute 0: queue starts with (0, 0)
  • minute 1: rot (0, 1) and (1, 0)
  • minute 2: rot (0, 2) and (1, 1)
  • minute 3: rot (2, 1)
  • minute 4: rot (2, 2)

So the answer is 4.

Common mistakes

1. Starting BFS from only one rotten orange

That misses the fact that many rotten oranges spread at the same time.

2. Counting minutes for every node instead of every layer

In BFS, one full queue layer represents one minute here.

3. Forgetting to track unreachable fresh oranges

Even if BFS finishes, you still need to check whether some fresh orange never got infected.

Complexity

Time Complexity: O(rows * cols)

Space Complexity: O(rows * cols)

Every cell is processed at most once, and the queue can hold a large part of the grid in the worst case.

Dynamic Programming

7 DP Patterns > 100 LeetCode Questions

Most DP questions are repeated ideas. Stop treating DP like chaos. Learn the 7 repeatable patterns that unlock most placement-level questions.

7 patternsProgress tracking
Read 7 patterns (5 min)