2Brute2Best
🔥0

Rotting Oranges

Medium·LeetCode #994Basic Anchor
LeetCode
30-Second Mental ModelMulti-source BFS (level by level)
Complexity:O((R · C)²)→O(R · C)
Key Insight

Put all the rotten oranges in a queue at minute 0. Pop one level at a time. Each level is one minute: every fresh neighbour of a popped orange rots and joins the queue for the next minute. Stop when no fresh orange is left. If the queue empties first, return -1.

Core Validity Invariant

At the start of a level, the queue holds exactly the oranges that rotted in the previous minute, so popping that many cells processes one whole minute and nothing from the next one.

01

Problem

You get a grid. Each cell is an empty cell, a fresh orange, or a rotten orange. Every minute, each fresh orange that touches a rotten orange on one of its four sides (up, down, left or right) rots as well.

Return the number of minutes until no fresh orange is left. If some fresh orange can never be reached by the rot, return -1.

Input

grid, an m × n grid. 0 = empty cell, 1 = fresh orange, 2 = rotten orange.

Output

The number of minutes until no fresh orange is left, or -1 if one of them never rots.

Example 1
Input: grid = [[2,1,1],[1,1,0],[0,1,1]]
Output: 4

Minute 1 rots the two oranges next to the top-left one. Minute 2 rots (0,2) and (1,1). Minute 3 rots (2,1), and minute 4 rots the last one, (2,2).

Example 2
Input: grid = [[2,1,1],[0,1,1],[1,0,1]]
Output: -1

The orange at (2,0) has only empty cells next to it, so no rot can ever reach it.

Example 3
Input: grid = [[0,2]]
Output: 0

There is no fresh orange at the start, so no minute is needed.

Constraints
  • • The grid has m rows and n columns, with 1 ≤ m, n ≤ 10.
  • • Each cell is 0, 1 or 2.
02

First, think yourself

Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.

  1. 1.

    If only one rotten orange starts the rot, how many minutes does it need to reach a fresh orange? What does that number measure?

  2. 2.

    What if two rotten oranges sit far apart? Does a fresh orange wait for the rot from just one of them?

  3. 3.

    How could I simulate the grid minute by minute? What would I have to look at in each minute?

  4. 4.

    Which oranges rot in minute 2? Can I find them without scanning the whole grid again?

  5. 5.

    How would I know the rot can never finish? What would still be on the grid at the end?

03

Brute force approach

05

Optimized approach

06

Why does this algorithm work?

07

Dry run

08

All approaches compared

ApproachIdeaTimeSpace
Brute ForceEach minute, scan the whole grid and rot the fresh oranges that touch a rotten oneO((R · C)²)O(R · C)
OptimalPut every rotten orange in the queue at once; each BFS level is one minuteO(R · C)O(R · C)
09

Why does this belong to this pattern?

Clues in the problem statement
  • “every rotten orange, all at once”Several starting points spread at the same time, so all of them go into the queue first.
  • “each minute, the four neighbours”One step on the grid is one minute, so one BFS level is one minute.
  • “minimum number of minutes”Each orange rots at its shortest distance from the nearest rotten orange, which is what BFS measures.
  • “return -1 if some orange never rots”If the queue runs dry while fresh oranges are left, those oranges were never reached.
Grid cells as nodes+many sources at distance 0+one BFS level = one minute+answer = the last level that rots something→Multi-source BFS (level by level)

This is the anchor of Multi-source BFS. Start one BFS with every rotten orange already in the queue, because the rot spreads from all of them together. The answer is the number of levels, which is the time for the rot to reach the last orange from its nearest rotten neighbour. A flood-fill question asks only which cells are connected; this question also counts the levels.

10

Don't make this mistake

Pattern confusion: a BFS from each rotten orange, then combining the answers
✗ for (auto [r, c] : rotten) answer = max(answer, bfsTimeFrom(r, c));
✓ queue = all rotten oranges at minute 0; one BFS over the whole grid

On the dry-run grid [[2,1,1,0],[1,1,0,2],[0,1,1,1]], a BFS from (0,0) alone needs 5 minutes and a BFS from (1,3) alone needs 6. Taking the maximum gives 6, but the real answer is 3. Each orange is reached by whichever rotten orange is nearest, and the two sources spread together.

Rotting during the scan
✗ for each cell: if it is fresh and touches a rotten cell, set it to 2 right away
✓ collect the cells first, then rot them after the scan (brute force)

On [[2,1,1],[1,1,0],[0,1,1]], scanning row by row rots (0,1) first, so (0,2) then touches a rotten cell and rots in minute 1. The whole grid rots in one sweep and the answer comes out as 1 instead of 4.

Forgetting the -1 case
✗ return minutes;
✓ return fresh == 0 ? minutes : -1;

On [[2,1,1],[0,1,1],[1,0,1]] the queue empties after 4 minutes, but the orange at (2,0) is still fresh. Returning minutes gives 4 instead of -1.

11

Want to implement this?

Write it yourself on LeetCode, then come back and compare your code with the solutions above.

Open coding workspace
How did it go?
Beyond The LeetCode Problem

How this concept connects to System Design & C++ Systems

Bridge DSA with production engineering

Top engineering interviews test whether you understand how algorithms like Graph BFS / DFS translate into production architectures and low-level memory mechanics.