🧠
Alternative Approach (DFS with time tracking)
💡 DFS can be used to simulate rot spread by recursively rotting adjacent fresh oranges and tracking the time taken. However, it is less natural and can be inefficient due to repeated visits and stack depth.
Intuition
For each rotten orange, recursively rot adjacent fresh oranges, passing the current time + 1. Track the maximum time needed to rot all oranges.
Algorithm
- Initialize max_time to 0.
- For each rotten orange, call DFS with time 0.
- In DFS, if current cell is fresh or can be rotted earlier, update its time and recurse to neighbors with time + 1.
- After DFS, check if any fresh orange remains; if yes, return -1 else return max_time.
💡 DFS requires careful time tracking and pruning to avoid infinite recursion and repeated work.
def orangesRotting(grid):
rows, cols = len(grid), len(grid[0])
time_grid = [[-1]*cols for _ in range(rows)]
max_time = 0
def dfs(r, c, time):
nonlocal max_time
if r < 0 or r >= rows or c < 0 or c >= cols:
return
if grid[r][c] == 0:
return
if time_grid[r][c] != -1 and time_grid[r][c] <= time:
return
time_grid[r][c] = time
max_time = max(max_time, time)
directions = [(1,0),(-1,0),(0,1),(0,-1)]
for dr, dc in directions:
nr, nc = r + dr, c + dc
if 0 <= nr < rows and 0 <= nc < cols:
if grid[nr][nc] == 1 or (grid[nr][nc] == 2 and time_grid[nr][nc] > time + 1):
dfs(nr, nc, time + 1)
for r in range(rows):
for c in range(cols):
if grid[r][c] == 2:
dfs(r, c, 0)
for r in range(rows):
for c in range(cols):
if grid[r][c] == 1 and time_grid[r][c] == -1:
return -1
return max_time
# Example usage
if __name__ == '__main__':
grid = [[2,1,1],[1,1,0],[0,1,1]]
print(orangesRotting(grid)) # Output: 4
Line Notes
time_grid = [[-1]*cols for _ in range(rows)]Track earliest time each cell gets rotten
def dfs(r, c, time):Recursive DFS function with current time
if time_grid[r][c] != -1 and time_grid[r][c] <= time:Prune if cell already rotted earlier or same time
time_grid[r][c] = timeUpdate time of rotting for current cell
max_time = max(max_time, time)Track maximum time across all cells
for dr, dc in directions:Explore all 4 adjacent cells
if 0 <= nr < rows and 0 <= nc < cols:Check boundaries before accessing grid
if grid[nr][nc] == 1 or (grid[nr][nc] == 2 and time_grid[nr][nc] > time + 1):Recurse if fresh or can be rotted earlier
for r in range(rows): for c in range(cols): if grid[r][c] == 2: dfs(r, c, 0)Start DFS from all rotten oranges
if grid[r][c] == 1 and time_grid[r][c] == -1: return -1If fresh orange never rotted, return -1
import java.util.*;
public class RottingOranges {
static int maxTime = 0;
static int rows, cols;
static int[][] timeGrid;
static int[][] grid;
static int[][] directions = {{1,0},{-1,0},{0,1},{0,-1}};
public static void dfs(int r, int c, int time) {
if (r < 0 || r >= rows || c < 0 || c >= cols) return;
if (grid[r][c] == 0) return;
if (timeGrid[r][c] != -1 && timeGrid[r][c] <= time) return;
timeGrid[r][c] = time;
maxTime = Math.max(maxTime, time);
for (int[] d : directions) {
int nr = r + d[0], nc = c + d[1];
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols) {
if (grid[nr][nc] == 1 || (grid[nr][nc] == 2 && timeGrid[nr][nc] > time + 1)) {
dfs(nr, nc, time + 1);
}
}
}
}
public static int orangesRotting(int[][] inputGrid) {
grid = inputGrid;
rows = grid.length;
cols = grid[0].length;
timeGrid = new int[rows][cols];
for (int[] row : timeGrid) Arrays.fill(row, -1);
maxTime = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (grid[r][c] == 2) dfs(r, c, 0);
}
}
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (grid[r][c] == 1 && timeGrid[r][c] == -1) return -1;
}
}
return maxTime;
}
public static void main(String[] args) {
int[][] grid = {{2,1,1},{1,1,0},{0,1,1}};
System.out.println(orangesRotting(grid)); // Output: 4
}
}
Line Notes
static int[][] timeGrid;Track earliest time each cell gets rotten
if (timeGrid[r][c] != -1 && timeGrid[r][c] <= time) return;Prune DFS if cell rotted earlier or same time
timeGrid[r][c] = time;Update rotting time for current cell
maxTime = Math.max(maxTime, time);Track maximum time across all cells
for (int[] d : directions) {Explore all 4 adjacent cells
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols) {Check boundaries before accessing grid
if (grid[nr][nc] == 1 || (grid[nr][nc] == 2 && timeGrid[nr][nc] > time + 1)) {Recurse if fresh or can be rotted earlier
for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { if (grid[r][c] == 2) dfs(r, c, 0); } }Start DFS from all rotten oranges
if (grid[r][c] == 1 && timeGrid[r][c] == -1) return -1;Return -1 if fresh orange never rotted
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int maxTime = 0;
int rows, cols;
vector<vector<int>> timeGrid;
vector<vector<int>> grid;
int directions[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
void dfs(int r, int c, int time) {
if (r < 0 || r >= rows || c < 0 || c >= cols) return;
if (grid[r][c] == 0) return;
if (timeGrid[r][c] != -1 && timeGrid[r][c] <= time) return;
timeGrid[r][c] = time;
maxTime = max(maxTime, time);
for (auto& d : directions) {
int nr = r + d[0], nc = c + d[1];
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols) {
if (grid[nr][nc] == 1 || (grid[nr][nc] == 2 && timeGrid[nr][nc] > time + 1)) {
dfs(nr, nc, time + 1);
}
}
}
}
int orangesRotting(vector<vector<int>>& inputGrid) {
grid = inputGrid;
rows = grid.size();
cols = grid[0].size();
timeGrid.assign(rows, vector<int>(cols, -1));
maxTime = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (grid[r][c] == 2) dfs(r, c, 0);
}
}
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (grid[r][c] == 1 && timeGrid[r][c] == -1) return -1;
}
}
return maxTime;
}
int main() {
vector<vector<int>> grid = {{2,1,1},{1,1,0},{0,1,1}};
cout << orangesRotting(grid) << endl; // Output: 4
return 0;
}
Line Notes
vector<vector<int>> timeGrid;Track earliest time each cell gets rotten
if (timeGrid[r][c] != -1 && timeGrid[r][c] <= time) return;Prune DFS if cell rotted earlier or same time
timeGrid[r][c] = time;Update rotting time for current cell
maxTime = max(maxTime, time);Track maximum time across all cells
for (auto& d : directions) {Explore all 4 adjacent cells
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols) {Check boundaries before accessing grid
if (grid[nr][nc] == 1 || (grid[nr][nc] == 2 && timeGrid[nr][nc] > time + 1)) {Recurse if fresh or can be rotted earlier
for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { if (grid[r][c] == 2) dfs(r, c, 0); } }Start DFS from all rotten oranges
if (grid[r][c] == 1 && timeGrid[r][c] == -1) return -1;Return -1 if fresh orange never rotted
function orangesRotting(grid) {
const rows = grid.length, cols = grid[0].length;
const timeGrid = Array.from({length: rows}, () => Array(cols).fill(-1));
let maxTime = 0;
function dfs(r, c, time) {
if (r < 0 || r >= rows || c < 0 || c >= cols) return;
if (grid[r][c] === 0) return;
if (timeGrid[r][c] !== -1 && timeGrid[r][c] <= time) return;
timeGrid[r][c] = time;
maxTime = Math.max(maxTime, time);
const directions = [[1,0],[-1,0],[0,1],[0,-1]];
for (const [dr, dc] of directions) {
const nr = r + dr, nc = c + dc;
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols) {
if (grid[nr][nc] === 1 || (grid[nr][nc] === 2 && timeGrid[nr][nc] > time + 1)) {
dfs(nr, nc, time + 1);
}
}
}
}
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
if (grid[r][c] === 2) dfs(r, c, 0);
}
}
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
if (grid[r][c] === 1 && timeGrid[r][c] === -1) return -1;
}
}
return maxTime;
}
// Example usage
console.log(orangesRotting([[2,1,1],[1,1,0],[0,1,1]])); // Output: 4
Line Notes
const timeGrid = Array.from({length: rows}, () => Array(cols).fill(-1));Track earliest time each cell gets rotten
if (timeGrid[r][c] !== -1 && timeGrid[r][c] <= time) return;Prune DFS if cell rotted earlier or same time
timeGrid[r][c] = time;Update rotting time for current cell
maxTime = Math.max(maxTime, time);Track maximum time across all cells
for (const [dr, dc] of directions) {Explore all 4 adjacent cells
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols) {Check boundaries before accessing grid
if (grid[nr][nc] === 1 || (grid[nr][nc] === 2 && timeGrid[nr][nc] > time + 1)) {Recurse if fresh or can be rotted earlier
for (let r = 0; r < rows; r++) { for (let c = 0; c < cols; c++) { if (grid[r][c] === 2) dfs(r, c, 0); } }Start DFS from all rotten oranges
if (grid[r][c] === 1 && timeGrid[r][c] === -1) return -1;Return -1 if fresh orange never rotted
TimeO(m * n * 4) worst case due to recursive calls and pruning
SpaceO(m * n) for recursion stack and time grid
DFS may revisit cells multiple times but pruning limits redundant calls; still less efficient than BFS
💡 For a 10x10 grid, recursion depth and repeated calls can cause stack overflow or inefficiency.
Interview Verdict: Accepted but less efficient and less natural than BFS
DFS works but is not the preferred approach due to complexity and potential stack issues.