Minutes until every item on a shelf spoils

Graphs Mid-level Python 3.13+ Kotlin 2.4+ Reviewed By Best Latest Apps

Fill the blank

Fill the blank so the queue starts with every spoiled item.

Python 3.13
from collections import deque
shelf = [[2, 1, 1], [1, 1, 0], [0, 1, 2]]
q = deque(____)
print(list(q))

Options

Choose an answer, then open Show answer below to check it.

Show answer

Answer: A (r, c) for r, row in enumerate(shelf) for c, v in enumerate(row) if v == 2

Right: every spoiled item is a starting point at minute 0.

Seeding the queue with all sources at once is what turns BFS into nearest-source distances.

Why not the others?
  • B [(0, 0)]. That only seeds the corner and misses the second spoiled item.
  • C (r, c) for r, row in enumerate(shelf) for c, v in enumerate(row) if v == 1. Fresh items are the targets, not the sources.
Spoiling spreads from the spoiled items one layer per minute across two small shelves.

Steps come from running the Python solution.

Text version

One source:

Grid (✕ = blocked): □□□ / □□✕ / ✕□□.

  1. Visit (0, 0), frontier 1. Start: 1 source cell at distance 0
  2. Visit (1, 0), (0, 1), frontier 2. Distance 1: 2 new cells
  3. Visit (1, 1), (0, 2), frontier 2. Distance 2: 2 new cells
  4. Visit (2, 1), frontier 1. Distance 3: 1 new cell
  5. Visit (2, 2), frontier 1. Distance 4: 1 new cell

Result: 4

Two sources:

Grid (✕ = blocked): □□✕□ / ✕□□□ / □□✕□.

  1. Visit (0, 0), (2, 3), frontier 2. Start: 2 source cells at distance 0
  2. Visit (0, 1), (1, 3), frontier 2. Distance 1: 2 new cells
  3. Visit (1, 1), (0, 3), (1, 2), frontier 3. Distance 2: 3 new cells
  4. Visit (2, 1), frontier 1. Distance 3: 1 new cell
  5. Visit (2, 0), frontier 1. Distance 4: 1 new cell

Result: 4

30-second answer

Put every spoiled item in a queue at once (multi-source BFS). Process the queue one layer per minute, spoiling fresh neighbours and queueing them. Stop when nothing fresh remains; if fresh items are left when the queue empties, return -1. O(R·C) time and space.

Practise saying it · 45 s. No recording, just a timer

Explain multi-source BFS on a grid.

Say your answer out loud, then check which of these points you covered:

  • All sources in the queue
  • One layer per minute
  • -1 if fresh items remain

Deep dive

Starting from all sources together gives each cell its distance to the nearest source in one pass.

Running a separate BFS from each spoiled item would be O((R·C)²).

Counting fresh items up front makes the -1 check and the early stop easy.

Python solution Ran on Python 3.13.5 · mypy --strict
Python 3.13
from collections import deque


STEPS = ((1, 0), (-1, 0), (0, 1), (0, -1))


def minutes_to_spoil(shelf: list[list[int]]) -> int:
    rows, cols = len(shelf), len(shelf[0]) if shelf else 0
    grid = [row[:] for row in shelf]
    queue = deque((r, c) for r, row in enumerate(grid)
                  for c, item in enumerate(row) if item == 2)
    fresh = sum(row.count(1) for row in grid)
    minutes = 0
    while queue and fresh:
        minutes += 1
        for _ in range(len(queue)):
            r, c = queue.popleft()
            for dr, dc in STEPS:
                y, x = r + dr, c + dc
                if 0 <= y < rows and 0 <= x < cols and grid[y][x] == 1:
                    grid[y][x] = 2
                    fresh -= 1
                    queue.append((y, x))
    return minutes if fresh == 0 else -1

Kotlin Ran on Kotlin 2.4.21 · JDK 21.0.12.1
Kotlin 2.4
val STEPS = listOf(1 to 0, -1 to 0, 0 to 1, 0 to -1)

fun minutesToSpoil(shelf: List<List<Int>>): Int {
    val grid = shelf.map { it.toMutableList() }
    val queue = ArrayDeque<Pair<Int, Int>>()
    var fresh = 0
    for ((r, row) in grid.withIndex()) {
        for ((c, item) in row.withIndex()) {
            if (item == 2) queue.addLast(r to c)
            if (item == 1) fresh++
        }
    }
    var minutes = 0
    while (queue.isNotEmpty() && fresh > 0) {
        minutes++
        repeat(queue.size) {
            val (r, c) = queue.removeFirst()
            for ((dr, dc) in STEPS) {
                val y = r + dr
                val x = c + dc
                if (grid.getOrNull(y)?.getOrNull(x) != 1) continue
                grid[y][x] = 2
                fresh--
                queue.addLast(y to x)
            }
        }
    }
    return if (fresh == 0) minutes else -1
}

Common mistakes

  • Counting a minute for the last layer even when it spoils nothing.
  • Forgetting that a shelf with no fresh items needs 0 minutes.

Senior take & follow-ups

Name it multi-source BFS. It is a recognisable pattern and interviewers like to hear the term.

Follow-up questions

Think of your answer first, then open the hint.

  1. How would you report each cell's spoil time?

    Show hint

    Store the BFS distance per cell instead of a single counter.

  2. What if some cells spoil faster?

    Show hint

    Then edges have weights; use Dijkstra or 0-1 BFS.

See it animated on iPhone (Breadth First Search in DSA Master - Data & Algorithms)

What each operation costs: Breadth First Search · Depth First Search · Topological Sort · Dijkstra Algorithm

From the author

DSA Master - Data & Algorithms

Free on iPhone and iPad: watch 50+ data structures and algorithms step through animations, run the code in the playground, and try the daily challenge.

Suggest a fix if something here is wrong or out of date.