Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
You are given an m x n grid where each cell can have one of three values:
0 representing an empty cell,1 representing a fresh orange, or2 representing a rotten orange.Every minute, any fresh orange that is 4-directionally adjacent to a rotten orange becomes rotten.
Return the minimum number of minutes that must elapse until no cell has a fresh orange. If this is impossible, return -1.
Example 1:
Input: grid = [[2,1,1],[1,1,0],[0,1,1]] Output: 4
Example 2:
Input: grid = [[2,1,1],[0,1,1],[1,0,1]] Output: -1 Explanation: The orange in the bottom left corner (row 2, column 0) is never rotten, because rotting only happens 4-directionally.
Example 3:
Input: grid = [[0,2]] Output: 0 Explanation: Since there are already no fresh oranges at minute 0, the answer is just 0.
Constraints:
m == grid.lengthn == grid[i].length1 <= m, n <= 10grid[i][j] is 0, 1, or 2.Problem summary: You are given an m x n grid where each cell can have one of three values: 0 representing an empty cell, 1 representing a fresh orange, or 2 representing a rotten orange. Every minute, any fresh orange that is 4-directionally adjacent to a rotten orange becomes rotten. Return the minimum number of minutes that must elapse until no cell has a fresh orange. If this is impossible, return -1.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array
[[2,1,1],[1,1,0],[0,1,1]]
[[2,1,1],[0,1,1],[1,0,1]]
[[0,2]]
walls-and-gates)battleships-in-a-board)detonate-the-maximum-bombs)escape-the-spreading-fire)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #994: Rotting Oranges
class Solution {
public int orangesRotting(int[][] grid) {
int m = grid.length, n = grid[0].length;
Deque<int[]> q = new ArrayDeque<>();
int cnt = 0;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (grid[i][j] == 1) {
++cnt;
} else if (grid[i][j] == 2) {
q.offer(new int[] {i, j});
}
}
}
final int[] dirs = {-1, 0, 1, 0, -1};
for (int ans = 1; !q.isEmpty() && cnt > 0; ++ans) {
for (int k = q.size(); k > 0; --k) {
var p = q.poll();
for (int d = 0; d < 4; ++d) {
int x = p[0] + dirs[d], y = p[1] + dirs[d + 1];
if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1) {
grid[x][y] = 2;
q.offer(new int[] {x, y});
if (--cnt == 0) {
return ans;
}
}
}
}
}
return cnt > 0 ? -1 : 0;
}
}
// Accepted solution for LeetCode #994: Rotting Oranges
func orangesRotting(grid [][]int) int {
m, n := len(grid), len(grid[0])
q := [][2]int{}
cnt := 0
for i, row := range grid {
for j, x := range row {
if x == 1 {
cnt++
} else if x == 2 {
q = append(q, [2]int{i, j})
}
}
}
dirs := [5]int{-1, 0, 1, 0, -1}
for ans := 1; len(q) > 0 && cnt > 0; ans++ {
for k := len(q); k > 0; k-- {
p := q[0]
q = q[1:]
for d := 0; d < 4; d++ {
x, y := p[0]+dirs[d], p[1]+dirs[d+1]
if x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 {
grid[x][y] = 2
q = append(q, [2]int{x, y})
if cnt--; cnt == 0 {
return ans
}
}
}
}
}
if cnt > 0 {
return -1
}
return 0
}
# Accepted solution for LeetCode #994: Rotting Oranges
class Solution:
def orangesRotting(self, grid: List[List[int]]) -> int:
m, n = len(grid), len(grid[0])
cnt = 0
q = deque()
for i, row in enumerate(grid):
for j, x in enumerate(row):
if x == 2:
q.append((i, j))
elif x == 1:
cnt += 1
ans = 0
dirs = (-1, 0, 1, 0, -1)
while q and cnt:
ans += 1
for _ in range(len(q)):
i, j = q.popleft()
for a, b in pairwise(dirs):
x, y = i + a, j + b
if 0 <= x < m and 0 <= y < n and grid[x][y] == 1:
grid[x][y] = 2
q.append((x, y))
cnt -= 1
if cnt == 0:
return ans
return -1 if cnt else 0
// Accepted solution for LeetCode #994: Rotting Oranges
use std::collections::VecDeque;
impl Solution {
pub fn oranges_rotting(mut grid: Vec<Vec<i32>>) -> i32 {
let m = grid.len();
let n = grid[0].len();
let mut q = VecDeque::new();
let mut cnt = 0;
for i in 0..m {
for j in 0..n {
if grid[i][j] == 1 {
cnt += 1;
} else if grid[i][j] == 2 {
q.push_back((i, j));
}
}
}
let dirs = [-1, 0, 1, 0, -1];
for ans in 1.. {
if q.is_empty() || cnt == 0 {
break;
}
let mut size = q.len();
for _ in 0..size {
let (x, y) = q.pop_front().unwrap();
for d in 0..4 {
let nx = x as isize + dirs[d] as isize;
let ny = y as isize + dirs[d + 1] as isize;
if nx >= 0 && nx < m as isize && ny >= 0 && ny < n as isize {
let nx = nx as usize;
let ny = ny as usize;
if grid[nx][ny] == 1 {
grid[nx][ny] = 2;
q.push_back((nx, ny));
cnt -= 1;
if cnt == 0 {
return ans;
}
}
}
}
}
}
if cnt > 0 {
-1
} else {
0
}
}
}
// Accepted solution for LeetCode #994: Rotting Oranges
function orangesRotting(grid: number[][]): number {
const m: number = grid.length;
const n: number = grid[0].length;
const q: number[][] = [];
let cnt: number = 0;
for (let i: number = 0; i < m; ++i) {
for (let j: number = 0; j < n; ++j) {
if (grid[i][j] === 1) {
cnt++;
} else if (grid[i][j] === 2) {
q.push([i, j]);
}
}
}
const dirs: number[] = [-1, 0, 1, 0, -1];
for (let ans = 1; q.length && cnt; ++ans) {
const t: number[][] = [];
for (const [i, j] of q) {
for (let d = 0; d < 4; ++d) {
const [x, y] = [i + dirs[d], j + dirs[d + 1]];
if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] === 1) {
grid[x][y] = 2;
t.push([x, y]);
if (--cnt === 0) {
return ans;
}
}
}
}
q.splice(0, q.length, ...t);
}
return cnt > 0 ? -1 : 0;
}
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.