Skip to content

Commit e4581dd

Browse files
committed
Add Rotting Oranges BFS solution
1 parent af9aad3 commit e4581dd

2 files changed

Lines changed: 288 additions & 0 deletions

File tree

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package com.thealgorithms.datastructures.graphs;
2+
3+
import java.util.LinkedList;
4+
import java.util.Queue;
5+
6+
/**
7+
* Multi-source Breadth-First Search (BFS) implementation for the Rotting Oranges problem.
8+
*
9+
* <p>Given a grid where:
10+
* <ul>
11+
* <li>0 represents an empty cell</li>
12+
* <li>1 represents a fresh orange</li>
13+
* <li>2 represents a rotten orange</li>
14+
* </ul>
15+
*
16+
* <p>Returns the minimum number of minutes required for all fresh oranges
17+
* to become rotten. Returns {@code -1} if it is impossible.
18+
*
19+
* <p>Time Complexity: O(m × n)
20+
* <br>Space Complexity: O(m × n)
21+
*/
22+
public class RottingOranges {
23+
24+
private static final int[] DEL_ROW = {-1, 0, 1, 0};
25+
private static final int[] DEL_COL = {0, 1, 0, -1};
26+
27+
private static final class Cell {
28+
private final int row;
29+
private final int col;
30+
private final int minute;
31+
32+
Cell(int row, int col, int minute) {
33+
this.row = row;
34+
this.col = col;
35+
this.minute = minute;
36+
}
37+
}
38+
39+
/**
40+
* Executes the Rotting Oranges algorithm.
41+
*
42+
* @param grid the input grid
43+
* @return minimum minutes required to rot all fresh oranges,
44+
* or -1 if impossible
45+
*/
46+
public int run(int[][] grid) {
47+
48+
if (grid == null || grid.length == 0 || grid[0].length == 0) {
49+
return 0;
50+
}
51+
52+
int rows = grid.length;
53+
int cols = grid[0].length;
54+
55+
// Create a copy so original input is not modified
56+
int[][] copy = new int[rows][cols];
57+
58+
for (int i = 0; i < rows; i++) {
59+
copy[i] = grid[i].clone();
60+
}
61+
62+
Queue<Cell> queue = new LinkedList<>();
63+
int freshOranges = 0;
64+
65+
// Find all rotten oranges and count fresh oranges
66+
for (int row = 0; row < rows; row++) {
67+
for (int col = 0; col < cols; col++) {
68+
69+
if (copy[row][col] == 2) {
70+
queue.offer(new Cell(row, col, 0));
71+
} else if (copy[row][col] == 1) {
72+
freshOranges++;
73+
}
74+
}
75+
}
76+
77+
if (freshOranges == 0) {
78+
return 0;
79+
}
80+
81+
int rottedFresh = 0;
82+
int minutes = 0;
83+
84+
// Multi-source BFS
85+
while (!queue.isEmpty()) {
86+
87+
Cell current = queue.poll();
88+
89+
minutes = Math.max(minutes, current.minute);
90+
91+
for (int i = 0; i < 4; i++) {
92+
93+
int newRow = current.row + DEL_ROW[i];
94+
int newCol = current.col + DEL_COL[i];
95+
96+
if (newRow >= 0
97+
&& newRow < rows
98+
&& newCol >= 0
99+
&& newCol < cols
100+
&& copy[newRow][newCol] == 1) {
101+
102+
copy[newRow][newCol] = 2;
103+
rottedFresh++;
104+
105+
queue.offer(new Cell(newRow, newCol, current.minute + 1));
106+
}
107+
}
108+
}
109+
110+
return rottedFresh == freshOranges ? minutes : -1;
111+
}
112+
}
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
package com.thealgorithms.datastructures.graphs;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
public class RottingOrangesTest {
8+
9+
@Test
10+
void testAllOrangesRotInSingleMinute() {
11+
RottingOranges rottingOranges = new RottingOranges();
12+
13+
int[][] grid = {
14+
{2, 1, 1},
15+
{1, 1, 0},
16+
{0, 1, 1}
17+
};
18+
19+
assertEquals(4, rottingOranges.run(grid));
20+
}
21+
22+
@Test
23+
void testImpossibleToRotAllOranges() {
24+
RottingOranges rottingOranges = new RottingOranges();
25+
26+
int[][] grid = {
27+
{2, 1, 1},
28+
{0, 1, 1},
29+
{1, 0, 1}
30+
};
31+
32+
assertEquals(-1, rottingOranges.run(grid));
33+
}
34+
35+
@Test
36+
void testNoFreshOranges() {
37+
RottingOranges rottingOranges = new RottingOranges();
38+
39+
int[][] grid = {
40+
{2, 2},
41+
{2, 2}
42+
};
43+
44+
assertEquals(0, rottingOranges.run(grid));
45+
}
46+
47+
@Test
48+
void testNoRottenOranges() {
49+
RottingOranges rottingOranges = new RottingOranges();
50+
51+
int[][] grid = {
52+
{1, 1},
53+
{1, 1}
54+
};
55+
56+
assertEquals(-1, rottingOranges.run(grid));
57+
}
58+
59+
@Test
60+
void testEmptyGrid() {
61+
RottingOranges rottingOranges = new RottingOranges();
62+
63+
int[][] grid = {};
64+
65+
assertEquals(0, rottingOranges.run(grid));
66+
}
67+
68+
@Test
69+
void testSingleRottenOrange() {
70+
RottingOranges rottingOranges = new RottingOranges();
71+
72+
int[][] grid = {
73+
{2}
74+
};
75+
76+
assertEquals(0, rottingOranges.run(grid));
77+
}
78+
79+
@Test
80+
void testSingleFreshOrange() {
81+
RottingOranges rottingOranges = new RottingOranges();
82+
83+
int[][] grid = {
84+
{1}
85+
};
86+
87+
assertEquals(-1, rottingOranges.run(grid));
88+
}
89+
90+
@Test
91+
void testSingleFreshOrangeNextToRottenOrange() {
92+
RottingOranges rottingOranges = new RottingOranges();
93+
94+
int[][] grid = {
95+
{2, 1}
96+
};
97+
98+
assertEquals(1, rottingOranges.run(grid));
99+
}
100+
101+
@Test
102+
void testMultipleRottenSources() {
103+
RottingOranges rottingOranges = new RottingOranges();
104+
105+
int[][] grid = {
106+
{2, 1, 0, 2},
107+
{1, 1, 1, 1},
108+
{0, 1, 1, 1}
109+
};
110+
111+
assertEquals(3, rottingOranges.run(grid));
112+
}
113+
114+
@Test
115+
void testFreshOrangeBlockedByEmptyCells() {
116+
RottingOranges rottingOranges = new RottingOranges();
117+
118+
int[][] grid = {
119+
{2, 0, 1},
120+
{0, 0, 0},
121+
{1, 0, 1}
122+
};
123+
124+
assertEquals(-1, rottingOranges.run(grid));
125+
}
126+
127+
@Test
128+
void testLinearSpread() {
129+
RottingOranges rottingOranges = new RottingOranges();
130+
131+
int[][] grid = {
132+
{2, 1, 1, 1, 1}
133+
};
134+
135+
assertEquals(4, rottingOranges.run(grid));
136+
}
137+
138+
@Test
139+
void testVerticalSpread() {
140+
RottingOranges rottingOranges = new RottingOranges();
141+
142+
int[][] grid = {
143+
{2},
144+
{1},
145+
{1},
146+
{1}
147+
};
148+
149+
assertEquals(3, rottingOranges.run(grid));
150+
}
151+
152+
@Test
153+
void testGridWithOnlyEmptyCells() {
154+
RottingOranges rottingOranges = new RottingOranges();
155+
156+
int[][] grid = {
157+
{0, 0},
158+
{0, 0}
159+
};
160+
161+
assertEquals(0, rottingOranges.run(grid));
162+
}
163+
164+
@Test
165+
void testComplexGrid() {
166+
RottingOranges rottingOranges = new RottingOranges();
167+
168+
int[][] grid = {
169+
{2, 1, 1},
170+
{1, 1, 1},
171+
{1, 1, 1}
172+
};
173+
174+
assertEquals(4, rottingOranges.run(grid));
175+
}
176+
}

0 commit comments

Comments
 (0)