From e4581ddf8c727494969d58c11aa98b9bec2b2e2f Mon Sep 17 00:00:00 2001 From: = Date: Sat, 25 Jul 2026 22:35:32 +0530 Subject: [PATCH 1/4] Add Rotting Oranges BFS solution --- .../datastructures/graphs/RottingOranges.java | 112 +++++++++++ .../graphs/RottingOrangesTest.java | 176 ++++++++++++++++++ 2 files changed, 288 insertions(+) create mode 100644 src/main/java/com/thealgorithms/datastructures/graphs/RottingOranges.java create mode 100644 src/test/java/com/thealgorithms/datastructures/graphs/RottingOrangesTest.java diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/RottingOranges.java b/src/main/java/com/thealgorithms/datastructures/graphs/RottingOranges.java new file mode 100644 index 000000000000..71b5bb493e77 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/graphs/RottingOranges.java @@ -0,0 +1,112 @@ +package com.thealgorithms.datastructures.graphs; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * Multi-source Breadth-First Search (BFS) implementation for the Rotting Oranges problem. + * + *

Given a grid where: + *

+ * + *

Returns the minimum number of minutes required for all fresh oranges + * to become rotten. Returns {@code -1} if it is impossible. + * + *

Time Complexity: O(m × n) + *
Space Complexity: O(m × n) + */ +public class RottingOranges { + + private static final int[] DEL_ROW = {-1, 0, 1, 0}; + private static final int[] DEL_COL = {0, 1, 0, -1}; + + private static final class Cell { + private final int row; + private final int col; + private final int minute; + + Cell(int row, int col, int minute) { + this.row = row; + this.col = col; + this.minute = minute; + } + } + + /** + * Executes the Rotting Oranges algorithm. + * + * @param grid the input grid + * @return minimum minutes required to rot all fresh oranges, + * or -1 if impossible + */ + public int run(int[][] grid) { + + if (grid == null || grid.length == 0 || grid[0].length == 0) { + return 0; + } + + int rows = grid.length; + int cols = grid[0].length; + + // Create a copy so original input is not modified + int[][] copy = new int[rows][cols]; + + for (int i = 0; i < rows; i++) { + copy[i] = grid[i].clone(); + } + + Queue queue = new LinkedList<>(); + int freshOranges = 0; + + // Find all rotten oranges and count fresh oranges + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + + if (copy[row][col] == 2) { + queue.offer(new Cell(row, col, 0)); + } else if (copy[row][col] == 1) { + freshOranges++; + } + } + } + + if (freshOranges == 0) { + return 0; + } + + int rottedFresh = 0; + int minutes = 0; + + // Multi-source BFS + while (!queue.isEmpty()) { + + Cell current = queue.poll(); + + minutes = Math.max(minutes, current.minute); + + for (int i = 0; i < 4; i++) { + + int newRow = current.row + DEL_ROW[i]; + int newCol = current.col + DEL_COL[i]; + + if (newRow >= 0 + && newRow < rows + && newCol >= 0 + && newCol < cols + && copy[newRow][newCol] == 1) { + + copy[newRow][newCol] = 2; + rottedFresh++; + + queue.offer(new Cell(newRow, newCol, current.minute + 1)); + } + } + } + + return rottedFresh == freshOranges ? minutes : -1; + } +} \ No newline at end of file diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/RottingOrangesTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/RottingOrangesTest.java new file mode 100644 index 000000000000..4c26ac3d9716 --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/graphs/RottingOrangesTest.java @@ -0,0 +1,176 @@ +package com.thealgorithms.datastructures.graphs; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class RottingOrangesTest { + + @Test + void testAllOrangesRotInSingleMinute() { + RottingOranges rottingOranges = new RottingOranges(); + + int[][] grid = { + {2, 1, 1}, + {1, 1, 0}, + {0, 1, 1} + }; + + assertEquals(4, rottingOranges.run(grid)); + } + + @Test + void testImpossibleToRotAllOranges() { + RottingOranges rottingOranges = new RottingOranges(); + + int[][] grid = { + {2, 1, 1}, + {0, 1, 1}, + {1, 0, 1} + }; + + assertEquals(-1, rottingOranges.run(grid)); + } + + @Test + void testNoFreshOranges() { + RottingOranges rottingOranges = new RottingOranges(); + + int[][] grid = { + {2, 2}, + {2, 2} + }; + + assertEquals(0, rottingOranges.run(grid)); + } + + @Test + void testNoRottenOranges() { + RottingOranges rottingOranges = new RottingOranges(); + + int[][] grid = { + {1, 1}, + {1, 1} + }; + + assertEquals(-1, rottingOranges.run(grid)); + } + + @Test + void testEmptyGrid() { + RottingOranges rottingOranges = new RottingOranges(); + + int[][] grid = {}; + + assertEquals(0, rottingOranges.run(grid)); + } + + @Test + void testSingleRottenOrange() { + RottingOranges rottingOranges = new RottingOranges(); + + int[][] grid = { + {2} + }; + + assertEquals(0, rottingOranges.run(grid)); + } + + @Test + void testSingleFreshOrange() { + RottingOranges rottingOranges = new RottingOranges(); + + int[][] grid = { + {1} + }; + + assertEquals(-1, rottingOranges.run(grid)); + } + + @Test + void testSingleFreshOrangeNextToRottenOrange() { + RottingOranges rottingOranges = new RottingOranges(); + + int[][] grid = { + {2, 1} + }; + + assertEquals(1, rottingOranges.run(grid)); + } + + @Test + void testMultipleRottenSources() { + RottingOranges rottingOranges = new RottingOranges(); + + int[][] grid = { + {2, 1, 0, 2}, + {1, 1, 1, 1}, + {0, 1, 1, 1} + }; + + assertEquals(3, rottingOranges.run(grid)); + } + + @Test + void testFreshOrangeBlockedByEmptyCells() { + RottingOranges rottingOranges = new RottingOranges(); + + int[][] grid = { + {2, 0, 1}, + {0, 0, 0}, + {1, 0, 1} + }; + + assertEquals(-1, rottingOranges.run(grid)); + } + + @Test + void testLinearSpread() { + RottingOranges rottingOranges = new RottingOranges(); + + int[][] grid = { + {2, 1, 1, 1, 1} + }; + + assertEquals(4, rottingOranges.run(grid)); + } + + @Test + void testVerticalSpread() { + RottingOranges rottingOranges = new RottingOranges(); + + int[][] grid = { + {2}, + {1}, + {1}, + {1} + }; + + assertEquals(3, rottingOranges.run(grid)); + } + + @Test + void testGridWithOnlyEmptyCells() { + RottingOranges rottingOranges = new RottingOranges(); + + int[][] grid = { + {0, 0}, + {0, 0} + }; + + assertEquals(0, rottingOranges.run(grid)); + } + + @Test + void testComplexGrid() { + RottingOranges rottingOranges = new RottingOranges(); + + int[][] grid = { + {2, 1, 1}, + {1, 1, 1}, + {1, 1, 1} + }; + + assertEquals(4, rottingOranges.run(grid)); + } +} \ No newline at end of file From f33695e67cc7f7e0ab1c13b6094941adc9656a9f Mon Sep 17 00:00:00 2001 From: = Date: Sat, 25 Jul 2026 22:49:19 +0530 Subject: [PATCH 2/4] Add reference URL to RottingOranges documentation --- .../thealgorithms/datastructures/graphs/RottingOranges.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/RottingOranges.java b/src/main/java/com/thealgorithms/datastructures/graphs/RottingOranges.java index 71b5bb493e77..e9d37d919c27 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/RottingOranges.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/RottingOranges.java @@ -6,6 +6,12 @@ /** * Multi-source Breadth-First Search (BFS) implementation for the Rotting Oranges problem. * + *

Algorithm explanation: + * https://en.wikipedia.org/wiki/Breadth-first_search + * + *

Problem reference: + * https://leetcode.com/problems/rotting-oranges/ + * *

Given a grid where: *