THN Interview Prep

994. Rotting Oranges

At a Glance

  • Topic: graphs
  • Pattern: BFS (multi-source, layered)
  • Difficulty: Medium
  • Companies: Amazon, Microsoft, Google, Meta, Apple
  • Frequency: High
  • LeetCode: 994

Problem (one-liner)

Grid 0 empty, 1 fresh orange, 2 rotten. Each minute, rotten infects 4-neighbors. Return minutes until no fresh remain, or -1 if impossible.

Recognition Cues

  • Simultaneous propagation — minute cadence = BFS levels
  • Multiple sources — enqueue all 2 initially

Diagram

At-a-glance flow (replace with problem-specific Mermaid as you refine this note). camelCase node IDs; no spaces in IDs.

Loading diagram…

Approaches

  • DFS timestamp — messy with correctness — avoid.
  • Optimal — multi-source BFS — O(nm) time, O(nm) queue.

Optimal Solution

Go

func orangesRotting(grid [][]int) int {
	rows := len(grid)
	cols := len(grid[0])
	queue := make([][2]int, 0)
	fresh := 0
	for row := 0; row < rows; row++ {
		for col := 0; col < cols; col++ {
			if grid[row][col] == 2 {
				queue = append(queue, [2]int{row, col})
			} else if grid[row][col] == 1 {
				fresh++
			}
		}
	}
	if fresh == 0 {
		return 0
	}
	minutesElapsed := 0
	directions := [][2]int{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}
	head := 0
	for len(queue)-head > 0 && fresh > 0 {
		waveCount := len(queue) - head
		for step := 0; step < waveCount; step++ {
			cell := queue[head]
			head++
			for _, delta := range directions {
				nextRow := cell[0] + delta[0]
				nextCol := cell[1] + delta[1]
				if nextRow < 0 || nextCol < 0 || nextRow >= rows || nextCol >= cols {
					continue
				}
				if grid[nextRow][nextCol] != 1 {
					continue
				}
				grid[nextRow][nextCol] = 2
				fresh--
				queue = append(queue, [2]int{nextRow, nextCol})
			}
		}
		minutesElapsed++
	}
	if fresh > 0 {
		return -1
	}
	return minutesElapsed
}

JavaScript

function orangesRotting(grid) {
  const rows = grid.length;
  const cols = grid[0].length;
  const queue = [];
  let fresh = 0;
  for (let row = 0; row < rows; row += 1) {
    for (let col = 0; col < cols; col += 1) {
      if (grid[row][col] === 2) {
        queue.push([row, col]);
      } else if (grid[row][col] === 1) {
        fresh += 1;
      }
    }
  }
  if (fresh === 0) {
    return 0;
  }
  const directions = [
    [1, 0],
    [-1, 0],
    [0, 1],
    [0, -1],
  ];
  let minutesElapsed = 0;
  let head = 0;
  while (queue.length - head > 0 && fresh > 0) {
    const waveCount = queue.length - head;
    for (let step = 0; step < waveCount; step += 1) {
      const cell = queue[head];
      head += 1;
      for (const [deltaRow, deltaCol] of directions) {
        const nextRow = cell[0] + deltaRow;
        const nextCol = cell[1] + deltaCol;
        if (nextRow < 0 || nextCol < 0 || nextRow >= rows || nextCol >= cols) {
          continue;
        }
        if (grid[nextRow][nextCol] !== 1) {
          continue;
        }
        grid[nextRow][nextCol] = 2;
        fresh -= 1;
        queue.push([nextRow, nextCol]);
      }
    }
    minutesElapsed += 1;
  }
  return fresh === 0 ? minutesElapsed : -1;
}

Walkthrough

Minute 0 rottens neighbors of initial layer; each round drains levelSize queue segment; stop when fresh==0.

Invariant: BFS layer index equals elapsed minutes for newly infected cells.

Edge Cases

  • Already all rotten / no fresh — 0
  • Unreachable fresh cell — -1

Pitfalls

  • Counting a minute when nothing changed in last layer — guard with fresh checks

Similar Problems

Variants

  • Hex grid — change neighbor offsets

Mind-Map Tags

#bfs #multi-source #grid #level-order #shortest-time

Last updated on

Spotted something unclear or wrong on this page?

On this page