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.length
n == grid[i].length
1 <= m, n <= 10
grid[i][j]
is 0
, 1
, or 2
.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
Imagine we have a grid of fresh and rotten oranges. The brute force approach is to simulate the rotting process minute by minute, checking at each step what happens to all the fresh oranges.
Here's how the algorithm would work step-by-step:
def rottingOranges(grid):
if not grid:
return -1
rows = len(grid)
cols = len(grid[0])
minutes_passed = 0
while True:
oranges_to_rot_this_minute = []
fresh_oranges_count = 0
previous_grid_snapshot = [row[:] for row in grid]
for row_index in range(rows):
for col_index in range(cols):
if previous_grid_snapshot[row_index][col_index] == 1:
fresh_oranges_count += 1
is_adjacent_to_rotten = False
# Check all four neighbors to see if any were rotten in the previous state.
for delta_row, delta_col in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
neighbor_row = row_index + delta_row
neighbor_col = col_index + delta_col
if 0 <= neighbor_row < rows and 0 <= neighbor_col < cols and previous_grid_snapshot[neighbor_row][neighbor_col] == 2:
is_adjacent_to_rotten = True
break
if is_adjacent_to_rotten:
oranges_to_rot_this_minute.append((row_index, col_index))
# If no oranges rotted this minute, the process stops.
if not oranges_to_rot_this_minute:
# If there are still fresh oranges left, it's impossible for them all to rot.
if fresh_oranges_count > 0:
return -1
else:
return minutes_passed
# Update the grid with all newly rotten oranges for the next minute's simulation.
for row_index, col_index in oranges_to_rot_this_minute:
grid[row_index][col_index] = 2
minutes_passed += 1
The problem is like a wave spreading outwards simultaneously from all the initially rotten oranges. We can simulate this wave, minute by minute, to see how long it takes for all the fresh oranges to get caught in it.
Here's how the algorithm would work step-by-step:
from collections import deque
def oranges_rotting(grid):
if not grid:
return 0
number_of_rows = len(grid)
number_of_cols = len(grid[0])
fresh_oranges_count = 0
rotten_oranges_queue = deque()
for row_index in range(number_of_rows):
for col_index in range(number_of_cols):
if grid[row_index][col_index] == 1:
fresh_oranges_count += 1
elif grid[row_index][col_index] == 2:
rotten_oranges_queue.append((row_index, col_index))
minutes_elapsed = 0
directions = [(1, 0), (-1, 0), (0, 1), (0, -1)]
# The queue size represents all oranges that become rotten in the current minute.
while rotten_oranges_queue and fresh_oranges_count > 0:
number_rotten_in_current_minute = len(rotten_oranges_queue)
for _ in range(number_rotten_in_current_minute):
rotten_row, rotten_col = rotten_oranges_queue.popleft()
for row_direction, col_direction in directions:
neighbor_row = rotten_row + row_direction
neighbor_col = rotten_col + col_direction
if 0 <= neighbor_row < number_of_rows and 0 <= neighbor_col < number_of_cols and grid[neighbor_row][neighbor_col] == 1:
grid[neighbor_row][neighbor_col] = 2
rotten_oranges_queue.append((neighbor_row, neighbor_col))
fresh_oranges_count -= 1
# Increment time only after all oranges from the current minute have spread rot.
minutes_elapsed += 1
# If fresh oranges remain, they were unreachable, so the task is impossible.
if fresh_oranges_count == 0:
return minutes_elapsed
else:
return -1
Case | How to Handle |
---|---|
Grid with no fresh oranges to begin with | The algorithm correctly returns 0 minutes since no time needs to pass. |
Grid with no rotten oranges to start, but fresh oranges exist | The rotting process can never start, so the solution must return -1 as it's impossible to rot all oranges. |
A fresh orange is isolated and cannot be reached by any rotten orange | After the BFS completes, the solution checks for any remaining fresh oranges and returns -1 if any are found. |
The input grid is empty (0 rows or 0 columns) | The initial scan for oranges will find none, leading to a correct return value of 0. |
The grid contains only empty cells (all 0s) | No fresh or rotten oranges exist, so the simulation correctly concludes in 0 minutes. |
All oranges in the grid are already rotten | No fresh oranges are found in the initial count, so the algorithm returns 0. |
A 1x1 grid containing a single fresh or rotten orange | The solution correctly handles this by returning -1 for a single fresh orange and 0 for a single rotten one. |
A large grid that requires an efficient solution | A Breadth-First Search (BFS) approach ensures scalability by visiting each cell at most once, performing efficiently within typical constraints. |