Skip to content

Commit c1699f0

Browse files
Merge branch 'master' into add-multinomial-naive-bayes
2 parents 1f1d98d + 38ff681 commit c1699f0

12 files changed

Lines changed: 301 additions & 24 deletions

File tree

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
steps:
1111
- uses: actions/checkout@v7
1212
- name: Set up JDK
13-
uses: actions/setup-java@v5.5.0
13+
uses: actions/setup-java@v5.6.0
1414
with:
1515
java-version: 21
1616
distribution: 'temurin'

.github/workflows/codeql.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,21 @@ jobs:
2424
uses: actions/checkout@v7
2525

2626
- name: Set up JDK
27-
uses: actions/setup-java@v5.5.0
27+
uses: actions/setup-java@v5.6.0
2828
with:
2929
java-version: 21
3030
distribution: 'temurin'
3131

3232
- name: Initialize CodeQL
33-
uses: github/codeql-action/init@v4.37.0
33+
uses: github/codeql-action/init@v4.37.3
3434
with:
3535
languages: 'java-kotlin'
3636

3737
- name: Build
3838
run: mvn --batch-mode --update-snapshots verify
3939

4040
- name: Perform CodeQL Analysis
41-
uses: github/codeql-action/analyze@v4.37.0
41+
uses: github/codeql-action/analyze@v4.37.3
4242
with:
4343
category: "/language:java-kotlin"
4444

@@ -55,12 +55,12 @@ jobs:
5555
uses: actions/checkout@v7
5656

5757
- name: Initialize CodeQL
58-
uses: github/codeql-action/init@v4.37.0
58+
uses: github/codeql-action/init@v4.37.3
5959
with:
6060
languages: 'actions'
6161

6262
- name: Perform CodeQL Analysis
63-
uses: github/codeql-action/analyze@v4.37.0
63+
uses: github/codeql-action/analyze@v4.37.3
6464
with:
6565
category: "/language:actions"
6666
...

.github/workflows/infer.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
- uses: actions/checkout@v7
1919

2020
- name: Set up JDK
21-
uses: actions/setup-java@v5.5.0
21+
uses: actions/setup-java@v5.6.0
2222
with:
2323
java-version: 21
2424
distribution: 'temurin'

.github/workflows/project_structure.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
runs-on: ubuntu-latest
1717
steps:
1818
- uses: actions/checkout@v7
19-
- uses: actions/setup-python@v6.3.0
19+
- uses: actions/setup-python@v7.0.0
2020
with:
2121
python-version: '3.13'
2222

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@
119119
<plugin>
120120
<groupId>com.github.spotbugs</groupId>
121121
<artifactId>spotbugs-maven-plugin</artifactId>
122-
<version>4.10.2.0</version>
122+
<version>4.10.3.0</version>
123123
<configuration>
124124
<excludeFilterFile>spotbugs-exclude.xml</excludeFilterFile>
125125
<includeTests>true</includeTests>

spotbugs-exclude.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@
5959
<Match>
6060
<Bug pattern="AT_STALE_THREAD_WRITE_OF_PRIMITIVE" />
6161
</Match>
62+
<Match>
63+
<Bug pattern="NP_NULL_PARAM_DEREF_NONVIRTUAL" />
64+
</Match>
65+
<Match>
66+
<Bug pattern="NP_NULL_PARAM_DEREF_ALL_TARGETS_DANGEROUS" />
67+
</Match>
6268
<!-- fb-contrib -->
6369
<Match>
6470
<Bug pattern="LSC_LITERAL_STRING_COMPARISON" />
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
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>Algorithm explanation:
10+
* https://en.wikipedia.org/wiki/Breadth-first_search
11+
*
12+
* <p>Problem reference:
13+
* https://leetcode.com/problems/rotting-oranges/
14+
*
15+
* <p>Given a grid where:
16+
* <ul>
17+
* <li>0 represents an empty cell</li>
18+
* <li>1 represents a fresh orange</li>
19+
* <li>2 represents a rotten orange</li>
20+
* </ul>
21+
*
22+
* <p>Returns the minimum number of minutes required for all fresh oranges
23+
* to become rotten. Returns {@code -1} if it is impossible.
24+
*
25+
* <p>Time Complexity: O(m × n)
26+
* <br>Space Complexity: O(m × n)
27+
*/
28+
public class RottingOranges {
29+
30+
private static final int[] DEL_ROW = {-1, 0, 1, 0};
31+
private static final int[] DEL_COL = {0, 1, 0, -1};
32+
33+
private static final class Cell {
34+
private final int row;
35+
private final int col;
36+
private final int minute;
37+
38+
Cell(int row, int col, int minute) {
39+
this.row = row;
40+
this.col = col;
41+
this.minute = minute;
42+
}
43+
}
44+
45+
/**
46+
* Executes the Rotting Oranges algorithm.
47+
*
48+
* @param grid the input grid
49+
* @return minimum minutes required to rot all fresh oranges,
50+
* or -1 if impossible
51+
*/
52+
public int run(int[][] grid) {
53+
54+
if (grid == null || grid.length == 0 || grid[0].length == 0) {
55+
return 0;
56+
}
57+
58+
int rows = grid.length;
59+
int cols = grid[0].length;
60+
61+
// Create a copy so original input is not modified
62+
int[][] copy = new int[rows][cols];
63+
64+
for (int i = 0; i < rows; i++) {
65+
copy[i] = grid[i].clone();
66+
}
67+
68+
Queue<Cell> queue = new LinkedList<>();
69+
int freshOranges = 0;
70+
71+
// Find all rotten oranges and count fresh oranges
72+
for (int row = 0; row < rows; row++) {
73+
for (int col = 0; col < cols; col++) {
74+
75+
if (copy[row][col] == 2) {
76+
queue.offer(new Cell(row, col, 0));
77+
} else if (copy[row][col] == 1) {
78+
freshOranges++;
79+
}
80+
}
81+
}
82+
83+
if (freshOranges == 0) {
84+
return 0;
85+
}
86+
87+
int rottedFresh = 0;
88+
int minutes = 0;
89+
90+
// Multi-source BFS
91+
while (!queue.isEmpty()) {
92+
93+
Cell current = queue.poll();
94+
95+
minutes = Math.max(minutes, current.minute);
96+
97+
for (int i = 0; i < 4; i++) {
98+
99+
int newRow = current.row + DEL_ROW[i];
100+
int newCol = current.col + DEL_COL[i];
101+
102+
if (newRow >= 0 && newRow < rows && newCol >= 0 && newCol < cols && copy[newRow][newCol] == 1) {
103+
104+
copy[newRow][newCol] = 2;
105+
rottedFresh++;
106+
107+
queue.offer(new Cell(newRow, newCol, current.minute + 1));
108+
}
109+
}
110+
}
111+
112+
return rottedFresh == freshOranges ? minutes : -1;
113+
}
114+
}
Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.thealgorithms.maths;
22

3-
import java.util.Arrays;
4-
53
public final class AbsoluteMin {
64
private AbsoluteMin() {
75
}
@@ -13,14 +11,17 @@ private AbsoluteMin() {
1311
* @return The absolute min value
1412
*/
1513
public static int getMinValue(int... numbers) {
16-
if (numbers.length == 0) {
17-
throw new IllegalArgumentException("Numbers array cannot be empty");
14+
if (numbers == null || numbers.length == 0) {
15+
throw new IllegalArgumentException("Numbers array cannot be empty or null");
1816
}
1917

20-
var absMinWrapper = new Object() { int value = numbers[0]; };
21-
22-
Arrays.stream(numbers).skip(1).filter(number -> Math.abs(number) <= Math.abs(absMinWrapper.value)).forEach(number -> absMinWrapper.value = Math.min(absMinWrapper.value, number));
23-
24-
return absMinWrapper.value;
18+
long absMin = numbers[0];
19+
for (int i = 1; i < numbers.length; i++) {
20+
long current = numbers[i];
21+
if (Math.abs(current) < Math.abs(absMin) || (Math.abs(current) == Math.abs(absMin) && current < absMin)) {
22+
absMin = current;
23+
}
24+
}
25+
return (int) absMin;
2526
}
2627
}

src/main/java/com/thealgorithms/maths/SumOfSquares.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
* Find minimum number of perfect squares that sum to given number
66
*
77
* @see <a href="https://en.wikipedia.org/wiki/Lagrange%27s_four-square_theorem">Lagrange's Four Square Theorem</a>
8-
* @author BEASTSHRIRAM
98
*/
109
public final class SumOfSquares {
1110

@@ -16,10 +15,15 @@ private SumOfSquares() {
1615
/**
1716
* Find minimum number of perfect squares that sum to n
1817
*
19-
* @param n the target number
18+
* @param n the target number (must be non-negative)
2019
* @return minimum number of squares needed
20+
* @throws IllegalArgumentException if n is negative
2121
*/
2222
public static int minSquares(int n) {
23+
if (n < 0) {
24+
throw new IllegalArgumentException("Input must be non-negative");
25+
}
26+
2327
if (isPerfectSquare(n)) {
2428
return 1;
2529
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
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 = {{2, 1, 1}, {1, 1, 0}, {0, 1, 1}};
14+
15+
assertEquals(4, rottingOranges.run(grid));
16+
}
17+
18+
@Test
19+
void testImpossibleToRotAllOranges() {
20+
RottingOranges rottingOranges = new RottingOranges();
21+
22+
int[][] grid = {{2, 1, 1}, {0, 1, 1}, {1, 0, 1}};
23+
24+
assertEquals(-1, rottingOranges.run(grid));
25+
}
26+
27+
@Test
28+
void testNoFreshOranges() {
29+
RottingOranges rottingOranges = new RottingOranges();
30+
31+
int[][] grid = {{2, 2}, {2, 2}};
32+
33+
assertEquals(0, rottingOranges.run(grid));
34+
}
35+
36+
@Test
37+
void testNoRottenOranges() {
38+
RottingOranges rottingOranges = new RottingOranges();
39+
40+
int[][] grid = {{1, 1}, {1, 1}};
41+
42+
assertEquals(-1, rottingOranges.run(grid));
43+
}
44+
45+
@Test
46+
void testEmptyGrid() {
47+
RottingOranges rottingOranges = new RottingOranges();
48+
49+
int[][] grid = {};
50+
51+
assertEquals(0, rottingOranges.run(grid));
52+
}
53+
54+
@Test
55+
void testSingleRottenOrange() {
56+
RottingOranges rottingOranges = new RottingOranges();
57+
58+
int[][] grid = {{2}};
59+
60+
assertEquals(0, rottingOranges.run(grid));
61+
}
62+
63+
@Test
64+
void testSingleFreshOrange() {
65+
RottingOranges rottingOranges = new RottingOranges();
66+
67+
int[][] grid = {{1}};
68+
69+
assertEquals(-1, rottingOranges.run(grid));
70+
}
71+
72+
@Test
73+
void testSingleFreshOrangeNextToRottenOrange() {
74+
RottingOranges rottingOranges = new RottingOranges();
75+
76+
int[][] grid = {{2, 1}};
77+
78+
assertEquals(1, rottingOranges.run(grid));
79+
}
80+
81+
@Test
82+
void testMultipleRottenSources() {
83+
RottingOranges rottingOranges = new RottingOranges();
84+
85+
int[][] grid = {{2, 1, 0, 2}, {1, 1, 1, 1}, {0, 1, 1, 1}};
86+
87+
assertEquals(3, rottingOranges.run(grid));
88+
}
89+
90+
@Test
91+
void testFreshOrangeBlockedByEmptyCells() {
92+
RottingOranges rottingOranges = new RottingOranges();
93+
94+
int[][] grid = {{2, 0, 1}, {0, 0, 0}, {1, 0, 1}};
95+
96+
assertEquals(-1, rottingOranges.run(grid));
97+
}
98+
99+
@Test
100+
void testLinearSpread() {
101+
RottingOranges rottingOranges = new RottingOranges();
102+
103+
int[][] grid = {{2, 1, 1, 1, 1}};
104+
105+
assertEquals(4, rottingOranges.run(grid));
106+
}
107+
108+
@Test
109+
void testVerticalSpread() {
110+
RottingOranges rottingOranges = new RottingOranges();
111+
112+
int[][] grid = {{2}, {1}, {1}, {1}};
113+
114+
assertEquals(3, rottingOranges.run(grid));
115+
}
116+
117+
@Test
118+
void testGridWithOnlyEmptyCells() {
119+
RottingOranges rottingOranges = new RottingOranges();
120+
121+
int[][] grid = {{0, 0}, {0, 0}};
122+
123+
assertEquals(0, rottingOranges.run(grid));
124+
}
125+
126+
@Test
127+
void testComplexGrid() {
128+
RottingOranges rottingOranges = new RottingOranges();
129+
130+
int[][] grid = {{2, 1, 1}, {1, 1, 1}, {1, 1, 1}};
131+
132+
assertEquals(4, rottingOranges.run(grid));
133+
}
134+
}

0 commit comments

Comments
 (0)