|
1 |
| -import java.util.HashSet; |
2 | 1 | import java.util.LinkedList;
|
3 |
| -import java.util.Objects; |
4 | 2 | import java.util.Queue;
|
5 |
| -import java.util.Set; |
6 | 3 |
|
7 | 4 | public class RottingOranges {
|
8 |
| - private static final int EMPTY_CELL = 0; |
| 5 | + private record RottenOrange(int row, int column, int time) {} |
| 6 | + |
9 | 7 | private static final int FRESH_ORANGE = 1;
|
10 | 8 | private static final int ROTTEN_ORANGE = 2;
|
11 | 9 |
|
12 |
| - private static final class Orange { |
13 |
| - private final int row; |
14 |
| - private final int column; |
15 |
| - private final int minutes; |
16 |
| - |
17 |
| - private Orange(int row, int column, int minutes) { |
18 |
| - this.row = row; |
19 |
| - this.column = column; |
20 |
| - this.minutes = minutes; |
21 |
| - } |
| 10 | + public int orangesRotting(int[][] grid) { |
| 11 | + final Queue<RottenOrange> queue = new LinkedList<>(); |
| 12 | + addAllRottenOrangesToQueue(grid, queue); |
| 13 | + int elapsedTime = 0; |
22 | 14 |
|
23 |
| - @Override |
24 |
| - public boolean equals(Object obj) { |
25 |
| - if (obj == this) return true; |
26 |
| - if (obj == null || obj.getClass() != this.getClass()) return false; |
27 |
| - var that = (Orange) obj; |
28 |
| - return this.row == that.row && this.column == that.column; |
| 15 | + while (!queue.isEmpty()) { |
| 16 | + RottenOrange orange = queue.poll(); |
| 17 | + addAdjacentOrangesInQueue(orange, queue, grid); |
| 18 | + elapsedTime = Math.max(elapsedTime, orange.time); |
29 | 19 | }
|
30 | 20 |
|
31 |
| - @Override |
32 |
| - public int hashCode() { |
33 |
| - return Objects.hash(row, column); |
34 |
| - } |
| 21 | + if (containsFreshOranges(grid)) return -1; |
| 22 | + return elapsedTime; |
35 | 23 | }
|
36 | 24 |
|
37 |
| - public static int orangesRotting(int[][] grid) { |
38 |
| - final Queue<Orange> oranges = allRottingOranges(grid); |
39 |
| - final Set<Orange> visited = new HashSet<>(); |
40 |
| - int result = 0; |
41 |
| - while (!oranges.isEmpty()) { |
42 |
| - Orange orange = oranges.poll(); |
43 |
| - if (!isValidPosition(orange, grid) || visited.contains(orange) || isEmptyCell(grid, orange)) { |
44 |
| - continue; |
| 25 | + private void addAllRottenOrangesToQueue(int[][] grid, final Queue<RottenOrange> queue) { |
| 26 | + for (int row = 0 ; row < grid.length ; row++) { |
| 27 | + for (int column = 0 ; column < grid[0].length ; column++) { |
| 28 | + if (isRottenOrange(grid[row][column])) { |
| 29 | + queue.add(new RottenOrange(row, column, 0)); |
| 30 | + } |
45 | 31 | }
|
46 |
| - visited.add(orange); |
47 |
| - grid[orange.row][orange.column] = ROTTEN_ORANGE; |
48 |
| - oranges.add(new Orange(orange.row - 1, orange.column, orange.minutes + 1)); |
49 |
| - oranges.add(new Orange(orange.row, orange.column + 1, orange.minutes + 1)); |
50 |
| - oranges.add(new Orange(orange.row + 1, orange.column, orange.minutes + 1)); |
51 |
| - oranges.add(new Orange(orange.row, orange.column - 1, orange.minutes + 1)); |
52 |
| - result = Math.max(result, orange.minutes); |
53 | 32 | }
|
54 |
| - if (allAreRotten(grid)) return result; |
55 |
| - return -1; |
56 | 33 | }
|
57 | 34 |
|
58 |
| - private static boolean allAreRotten(int[][] grid) { |
| 35 | + private boolean isRottenOrange(int orange) { |
| 36 | + return orange == ROTTEN_ORANGE; |
| 37 | + } |
| 38 | + |
| 39 | + private boolean isFreshOrange(int orange) { |
| 40 | + return orange == FRESH_ORANGE; |
| 41 | + } |
| 42 | + |
| 43 | + private boolean containsFreshOranges(int[][] grid) { |
59 | 44 | for (int[] row : grid) {
|
60 | 45 | for (int orange : row) {
|
61 |
| - if (orange == FRESH_ORANGE) return false; |
| 46 | + if (isFreshOrange(orange)) return true; |
62 | 47 | }
|
63 | 48 | }
|
64 |
| - return true; |
| 49 | + return false; |
65 | 50 | }
|
66 | 51 |
|
67 |
| - private static Queue<Orange> allRottingOranges(int[][] grid) { |
68 |
| - final Queue<Orange> rottenOranges = new LinkedList<>(); |
69 |
| - for (int row = 0 ; row < grid.length ; row++) { |
70 |
| - for (int column = 0 ; column < grid[0].length ; column++) { |
71 |
| - if (grid[row][column] == ROTTEN_ORANGE) { |
72 |
| - rottenOranges.add(new Orange(row, column, 0)); |
73 |
| - } |
74 |
| - } |
| 52 | + private void addAdjacentOrangesInQueue(RottenOrange orange, Queue<RottenOrange> queue, int[][] grid) { |
| 53 | + addOrangeOnTop(orange, queue, grid); |
| 54 | + addOrangeOnRight(orange, queue, grid); |
| 55 | + addOrangeOnBottom(orange, queue, grid); |
| 56 | + addOrangeOnLeft(orange, queue, grid); |
| 57 | + } |
| 58 | + |
| 59 | + private void addOrangeOnTop(RottenOrange orange, Queue<RottenOrange> queue, int[][] grid) { |
| 60 | + if (isValidPosition(grid, orange.row - 1, orange.column) && isFreshOrange(grid[orange.row - 1][orange.column])) { |
| 61 | + markRotten(grid, orange.row - 1, orange.column); |
| 62 | + queue.add(new RottenOrange(orange.row - 1, orange.column, orange.time + 1)); |
| 63 | + } |
| 64 | + } |
| 65 | + |
| 66 | + private void addOrangeOnRight(RottenOrange orange, Queue<RottenOrange> queue, int[][] grid) { |
| 67 | + if (isValidPosition(grid, orange.row, orange.column + 1) && isFreshOrange(grid[orange.row][orange.column + 1])) { |
| 68 | + markRotten(grid, orange.row, orange.column + 1); |
| 69 | + queue.add(new RottenOrange(orange.row, orange.column + 1, orange.time + 1)); |
| 70 | + } |
| 71 | + } |
| 72 | + |
| 73 | + private void addOrangeOnBottom(RottenOrange orange, Queue<RottenOrange> queue, int[][] grid) { |
| 74 | + if (isValidPosition(grid, orange.row + 1, orange.column) && isFreshOrange(grid[orange.row + 1][orange.column])) { |
| 75 | + markRotten(grid, orange.row + 1, orange.column); |
| 76 | + queue.add(new RottenOrange(orange.row + 1, orange.column, orange.time + 1)); |
75 | 77 | }
|
76 |
| - return rottenOranges; |
77 | 78 | }
|
78 | 79 |
|
79 |
| - private static boolean isValidPosition(Orange orange, int[][] grid) { |
80 |
| - return orange.row >= 0 && orange.row < grid.length && orange.column >= 0 && orange.column < grid[0].length; |
| 80 | + private void addOrangeOnLeft(RottenOrange orange, Queue<RottenOrange> queue, int[][] grid) { |
| 81 | + if (isValidPosition(grid, orange.row, orange.column - 1) && isFreshOrange(grid[orange.row][orange.column - 1])) { |
| 82 | + markRotten(grid, orange.row, orange.column - 1); |
| 83 | + queue.add(new RottenOrange(orange.row, orange.column - 1, orange.time + 1)); |
| 84 | + } |
81 | 85 | }
|
82 | 86 |
|
83 |
| - private static boolean isRotten(int[][] grid, Orange orange) { |
84 |
| - return grid[orange.row][orange.column] == ROTTEN_ORANGE; |
| 87 | + private boolean isValidPosition(int[][] grid, int row, int column) { |
| 88 | + return row >= 0 |
| 89 | + && row < grid.length |
| 90 | + && column >= 0 |
| 91 | + && column < grid[0].length; |
85 | 92 | }
|
86 | 93 |
|
87 |
| - private static boolean isEmptyCell(int[][] grid, Orange orange) { |
88 |
| - return grid[orange.row][orange.column] == EMPTY_CELL; |
| 94 | + private void markRotten(int[][] grid, int row, int column) { |
| 95 | + grid[row][column] = ROTTEN_ORANGE; |
89 | 96 | }
|
90 | 97 | }
|
0 commit comments