Skip to content

Commit 950172a

Browse files
committed
Rotting oranges
1 parent 6ae2e49 commit 950172a

File tree

2 files changed

+182
-0
lines changed

2 files changed

+182
-0
lines changed

994.rotting_oranges/oranges.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# 994. Rotting oranges
2+
# Topics: 'Array', 'Breadth-First Search', 'Matrix'
3+
# Level: 'Medium'
4+
5+
# You are given an m x n grid where each cell can have one of three values:
6+
7+
# 0 representing an empty cell,
8+
# 1 representing a fresh orange, or
9+
# 2 representing a rotten orange.
10+
11+
# Every minute, any fresh orange that is 4-directionally adjacent to a rotten orange becomes rotten.
12+
13+
# Return the minimum number of minutes that must elapse until no cell has a fresh orange. If this is impossible, return -1.
14+
15+
16+
17+
# Example 1:
18+
19+
# Input: grid = [[2,1,1],[1,1,0],[0,1,1]]
20+
# Output: 4
21+
22+
# Example 2:
23+
24+
# Input: grid = [[2,1,1],[0,1,1],[1,0,1]]
25+
# Output: -1
26+
# Explanation: The orange in the bottom left corner (row 2, column 0) is never rotten, because rotting only happens 4-directionally.
27+
28+
# Example 3:
29+
30+
# Input: grid = [[0,2]]
31+
# Output: 0
32+
# Explanation: Since there are already no fresh oranges at minute 0, the answer is just 0.
33+
34+
35+
36+
# Constraints:
37+
38+
# m == grid.length
39+
# n == grid[i].length
40+
# 1 <= m, n <= 10
41+
# grid[i][j] is 0, 1, or 2.
42+
43+
from collections import deque
44+
from typing import List
45+
46+
class Solution:
47+
def orangesRotting(self, grid: List[List[int]]) -> int:
48+
q = deque()
49+
fresh = 0
50+
for row in range (len(grid)):
51+
for col in range (len(grid[row])):
52+
if grid[row][col] == 2:
53+
q.append((row,col))
54+
if grid[row][col] == 1:
55+
fresh+=1
56+
if fresh == 0:
57+
return 0
58+
minutes = 0
59+
ROWS, COLS = len(grid), len(grid[0])
60+
while q:
61+
rotten = False
62+
for i in range (len(q)):
63+
row, col = q.popleft()
64+
directions = [[1, 0], [-1,0], [0, 1], [0,-1]]
65+
for dr, dc in directions:
66+
if min(row+dr, col+dc) < 0:
67+
continue
68+
if row+dr == ROWS or col+dc == COLS:
69+
continue
70+
if grid[row+dr][col+dc] != 1:
71+
continue
72+
grid[row+dr][col+dc] = 2
73+
q.append((row+dr,col+dc))
74+
rotten = True
75+
fresh-=1
76+
if rotten:
77+
minutes+=1
78+
if fresh > 0:
79+
return -1
80+
return minutes
81+
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
from collections import deque
2+
from typing import List
3+
import unittest
4+
from oranges import Solution
5+
6+
class TestOrangesRotting(unittest.TestCase):
7+
8+
def setUp(self):
9+
self.solution = Solution()
10+
11+
def test_example_1(self):
12+
"""Standard case with rotting spreading"""
13+
grid = [[2,1,1],[1,1,0],[0,1,1]]
14+
self.assertEqual(self.solution.orangesRotting(grid), 4)
15+
16+
def test_example_2(self):
17+
"""Impossible case - isolated fresh orange"""
18+
grid = [[2,1,1],[0,1,1],[1,0,1]]
19+
self.assertEqual(self.solution.orangesRotting(grid), -1)
20+
21+
def test_no_fresh_oranges(self):
22+
"""No fresh oranges to rot"""
23+
grid = [[0,2]]
24+
self.assertEqual(self.solution.orangesRotting(grid), 0)
25+
26+
def test_all_fresh_no_rotten(self):
27+
"""All fresh, no rotten oranges"""
28+
grid = [[1,1,1],[1,1,1]]
29+
self.assertEqual(self.solution.orangesRotting(grid), -1)
30+
31+
def test_all_rotten(self):
32+
"""All oranges already rotten"""
33+
grid = [[2,2],[2,2]]
34+
self.assertEqual(self.solution.orangesRotting(grid), 0)
35+
36+
def test_single_fresh(self):
37+
"""Single fresh orange next to rotten"""
38+
grid = [[2,1]]
39+
self.assertEqual(self.solution.orangesRotting(grid), 1)
40+
41+
def test_single_rotten(self):
42+
"""Only one rotten orange, no fresh"""
43+
grid = [[2]]
44+
self.assertEqual(self.solution.orangesRotting(grid), 0)
45+
46+
def test_single_fresh_alone(self):
47+
"""Single fresh orange, no rotten"""
48+
grid = [[1]]
49+
self.assertEqual(self.solution.orangesRotting(grid), -1)
50+
51+
def test_empty_cells_only(self):
52+
"""Grid with only empty cells"""
53+
grid = [[0,0],[0,0]]
54+
self.assertEqual(self.solution.orangesRotting(grid), 0)
55+
56+
def test_multiple_rotten_sources(self):
57+
"""Multiple rotten oranges spreading simultaneously"""
58+
grid = [[2,1,1],[1,1,1],[1,1,2]]
59+
self.assertEqual(self.solution.orangesRotting(grid), 2)
60+
61+
def test_long_chain(self):
62+
"""Linear chain of oranges"""
63+
grid = [[2,1,1,1,1,1]]
64+
self.assertEqual(self.solution.orangesRotting(grid), 5)
65+
66+
def test_isolated_groups(self):
67+
"""Fresh orange isolated by empty cells"""
68+
grid = [[2,1,0,1]]
69+
self.assertEqual(self.solution.orangesRotting(grid), -1)
70+
71+
def test_large_grid(self):
72+
"""Larger grid with complex pattern"""
73+
grid = [
74+
[2,1,1,0,0],
75+
[1,1,0,0,0],
76+
[0,0,0,1,2],
77+
[0,0,0,1,1]
78+
]
79+
self.assertEqual(self.solution.orangesRotting(grid), 2)
80+
81+
def test_square_grid(self):
82+
"""Rotten in center spreading outward"""
83+
grid = [
84+
[1,1,1],
85+
[1,2,1],
86+
[1,1,1]
87+
]
88+
self.assertEqual(self.solution.orangesRotting(grid), 2)
89+
90+
def test_corner_rotten(self):
91+
"""Rotten in corner"""
92+
grid = [
93+
[2,1,1],
94+
[1,1,1],
95+
[1,1,1]
96+
]
97+
self.assertEqual(self.solution.orangesRotting(grid), 4)
98+
99+
100+
if __name__ == '__main__':
101+
unittest.main()

0 commit comments

Comments
 (0)