Back to Graphs
Rotten Oranges
Rotten Oranges
🧩 Problem Statement
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 = [[0,2]]
Output:
0
🔍 Approaches
1. Multi-Source BFS
This problem asks for the minimum time to rot all oranges, which spreads level by level. This suggests BFS.
Since there can be multiple initially rotten oranges, we start BFS from all of them simultaneously.
Algorithm Steps:
- Initialize:
- Queue
q. freshCount = 0.time = 0.
- Scan Grid: Iterate through the grid.
- If cell is
2, add toq. - If cell is
1, incrementfreshCount.
- BFS:
- Loop while
qis not empty ANDfreshCount > 0. - Process level by level (size of queue).
- For each rotten orange, check 4 neighbors.
- If neighbor is fresh (
1): - Mark as rotten (
2). - Decrement
freshCount. - Add to
q. - After processing neighbors, increment
time.
- Final Check: If
freshCount == 0, returntime. Else, return-1.
Note: IffreshCountis 0 initially, return 0.
⏳ Time & Space Complexity
- Time Complexity: $O(M \cdot N)$. We visit each cell at most once.
- Space Complexity: $O(M \cdot N)$ for the queue.
🚀 Code Implementations
C++
#include <vector>
#include <queue>
using namespace std;
class Solution {
public:
int orangesRotting(vector<vector<int>>& grid) {
int m = grid.size();
int n = grid[0].size();
queue<pair<int, int>> q;
int freshCount = 0;
for(int i = 0; i < m; ++i) {
for(int j = 0; j < n; ++j) {
if(grid[i][j] == 2) {
q.push({i, j});
} else if(grid[i][j] == 1) {
freshCount++;
}
}
}
if(freshCount == 0) return 0;
int minutes = 0;
int directions[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
while(!q.empty() && freshCount > 0) {
int size = q.size();
while(size--) {
auto [r, c] = q.front();
q.pop();
for(auto& dir : directions) {
int nr = r + dir[0];
int nc = c + dir[1];
if(nr >= 0 && nr < m && nc >= 0 && nc < n && grid[nr][nc] == 1) {
grid[nr][nc] = 2; // Rot it
freshCount--;
q.push({nr, nc});
}
}
}
minutes++;
}
return freshCount == 0 ? minutes : -1;
}
};
Python
from typing import List
from collections import deque
class Solution:
def orangesRotting(self, grid: List[List[int]]) -> int:
rows, cols = len(grid), len(grid[0])
q = deque()
fresh_count = 0
for r in range(rows):
for c in range(cols):
if grid[r][c] == 2:
q.append((r, c))
elif grid[r][c] == 1:
fresh_count += 1
if fresh_count == 0:
return 0
minutes = 0
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
while q and fresh_count > 0:
for _ in range(len(q)):
r, c = q.popleft()
for dr, dc in directions:
nr, nc = r + dr, c + dc
if 0 <= nr < rows and 0 <= nc < cols and grid[nr][nc] == 1:
grid[nr][nc] = 2 # Rot it
fresh_count -= 1
q.append((nr, nc))
minutes += 1
return minutes if fresh_count == 0 else -1
Java
import java.util.LinkedList;
import java.util.Queue;
class Solution {
public int orangesRotting(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
Queue<int[]> q = new LinkedList<>();
int freshCount = 0;
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(grid[i][j] == 2) {
q.offer(new int[]{i, j});
} else if(grid[i][j] == 1) {
freshCount++;
}
}
}
if(freshCount == 0) return 0;
int minutes = 0;
int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
while(!q.isEmpty() && freshCount > 0) {
int size = q.size();
while(size-- > 0) {
int[] curr = q.poll();
int r = curr[0];
int c = curr[1];
for(int[] dir : directions) {
int nr = r + dir[0];
int nc = c + dir[1];
if(nr >= 0 && nr < m && nc >= 0 && nc < n && grid[nr][nc] == 1) {
grid[nr][nc] = 2; // Rot it
freshCount--;
q.offer(new int[]{nr, nc});
}
}
}
minutes++;
}
return freshCount == 0 ? minutes : -1;
}
}
🌍 Real-World Analogy
Zombie Apocalypse:
Fresh oranges are humans, rotten oranges are zombies.
- At time 0, multi-source infection starts.
- Zombies infect adjacent humans every minute.
- Can everyone be infected? If islanded humans exist, answer is impossible (-1).
🎯 Summary
✅ Multi-Source BFS: Start queue with ALL initial sources.
✅ Level Tracking: Increment time only after processing full queue snapshot.
Solution Code
O(n) TimeO(1) Space
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
class Solution {
public:
int orangesRotting(vector<vector<int>> &grid) {
int m = grid.size();
int n = grid[0].size();
queue<pair<int, int>> q;
int freshCount = 0;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (grid[i][j] == 2) {
q.push({i, j});
} else if (grid[i][j] == 1) {
freshCount++;
}
}
}
if (freshCount == 0)
return 0;
int minutes = 0;
int directions[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
while (!q.empty() && freshCount > 0) {
int size = q.size();
while (size--) {
auto [r, c] = q.front();
q.pop();
for (auto &dir : directions) {
int nr = r + dir[0];
int nc = c + dir[1];
if (nr >= 0 && nr < m && nc >= 0 && nc < n && grid[nr][nc] == 1) {
grid[nr][nc] = 2; // Rot it
freshCount--;
q.push({nr, nc});
}
}
}
minutes++;
}
return freshCount == 0 ? minutes : -1;
}
};
int main() {
Solution sol;
vector<vector<int>> grid1 = {{2, 1, 1}, {1, 1, 0}, {0, 1, 1}};
cout << "Rotten Oranges 1: " << sol.orangesRotting(grid1) << endl; // Expect 4
vector<vector<int>> grid2 = {{2, 1, 1}, {0, 1, 1}, {1, 0, 1}};
cout << "Rotten Oranges 2: " << sol.orangesRotting(grid2)
<< endl; // Expect -1
vector<vector<int>> grid3 = {{0, 2}};
cout << "Rotten Oranges 3: " << sol.orangesRotting(grid3) << endl; // Expect 0
return 0;
}
SYSTEM STABLEUTF-8 • STATIC_RENDER