Skip to content

Commit 12bd616

Browse files
Merge branch 'master' into add-happy-number
2 parents 9dfd203 + e788111 commit 12bd616

File tree

4 files changed

+377
-0
lines changed

4 files changed

+377
-0
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.thealgorithms.maths;
2+
3+
import com.thealgorithms.maths.Prime.PrimeCheck;
4+
5+
/**
6+
* A utility class to check whether a number is a Germain prime or a Safe prime.
7+
*
8+
* <p>This class provides methods to:
9+
* <ul>
10+
* <li>Check if a number is a Germain prime</li>
11+
* <li>Check if a number is a Safe prime</li>
12+
* </ul>
13+
*
14+
* <p>Definitions:
15+
* <ul>
16+
* <li>A Germain prime is a prime number p such that 2p + 1 is also prime.</li>
17+
* <li>A Safe prime is a prime number p such that (p - 1) / 2 is also prime.</li>
18+
* </ul>
19+
*
20+
* <p>This class is final and cannot be instantiated.
21+
*
22+
* @see <a href="https://en.wikipedia.org/wiki/Safe_and_Sophie_Germain_primes">Wikipedia: Safe and Sophie Germain primes</a>
23+
*/
24+
public final class GermainPrimeAndSafePrime {
25+
26+
// Private constructor to prevent instantiation
27+
private GermainPrimeAndSafePrime() {
28+
}
29+
30+
/**
31+
* Checks if a number is a Germain prime.
32+
*
33+
* <p>A Germain prime is a prime number p such that 2p + 1 is also prime.
34+
*
35+
* @param number the number to check; must be a positive integer
36+
* @return {@code true} if the number is a Germain prime, {@code false} otherwise
37+
* @throws IllegalArgumentException if the input number is less than 1
38+
*/
39+
public static boolean isGermainPrime(int number) {
40+
if (number < 1) {
41+
throw new IllegalArgumentException("Input value must be a positive integer. Input value: " + number);
42+
}
43+
// A number is a Germain prime if it is prime and 2 * number + 1 is also prime
44+
return PrimeCheck.isPrime(number) && PrimeCheck.isPrime(2 * number + 1);
45+
}
46+
47+
/**
48+
* Checks if a number is a Safe prime.
49+
*
50+
* <p>A Safe prime is a prime number p such that (p - 1) / 2 is also prime.
51+
*
52+
* @param number the number to check; must be a positive integer
53+
* @return {@code true} if the number is a Safe prime, {@code false} otherwise
54+
* @throws IllegalArgumentException if the input number is less than 1
55+
*/
56+
public static boolean isSafePrime(int number) {
57+
if (number < 1) {
58+
throw new IllegalArgumentException("Input value must be a positive integer. Input value: " + number);
59+
}
60+
// A number is a Safe prime if it is prime, (number - 1) is even, and (number - 1) / 2 is prime
61+
return ((number - 1) % 2 == 0) && PrimeCheck.isPrime(number) && PrimeCheck.isPrime((number - 1) / 2);
62+
}
63+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package com.thealgorithms.others;
2+
3+
import java.util.LinkedList;
4+
import java.util.Queue;
5+
6+
/**
7+
* Implementation of the Flood Fill algorithm using an iterative BFS (Breadth-First Search) approach.
8+
*
9+
* <p>The Flood Fill algorithm is used to fill connected areas in an image with a new color, starting from a specified point.
10+
* This implementation uses an iterative BFS approach with a queue
11+
* instead of recursion to avoid stack overflow issues with large images.</p>
12+
*
13+
* <p><b>Implementation Features:</b></p>
14+
* <ul>
15+
* <li>Supports 8-connected filling (horizontal, vertical, and diagonal directions)</li>
16+
* <li>Uses BFS traversal through {@link java.util.Queue}</li>
17+
* <li>Includes nested {@code Point} class to represent pixel coordinates</li>
18+
* <li>Iterative approach avoids stack overflow for large images</li>
19+
* </ul>
20+
*
21+
* <p><b>Time Complexity:</b> O(M × N) where M and N are the dimensions of the image</p>
22+
* <p><b>Space Complexity:</b> O(M × N) in the worst case the queue stores every pixel</p>
23+
*
24+
* @see <a href="https://www.geeksforgeeks.org/dsa/flood-fill-algorithm">Flood Fill Algorithm - GeeksforGeeks</a>
25+
* @see <a href="https://en.wikipedia.org/wiki/Flood_fill">Flood Fill Algorithm - Wikipedia</a>
26+
*/
27+
public final class IterativeFloodFill {
28+
private IterativeFloodFill() {
29+
}
30+
31+
/**
32+
* Iteratively fill the 2D image with new color
33+
*
34+
* @param image The image to be filled
35+
* @param x The x co-ordinate at which color is to be filled
36+
* @param y The y co-ordinate at which color is to be filled
37+
* @param newColor The new color which to be filled in the image
38+
* @param oldColor The old color which is to be replaced in the image
39+
* @see <a href=https://www.geeksforgeeks.org/dsa/flood-fill-algorithm>FloodFill BFS<a/>
40+
*/
41+
public static void floodFill(final int[][] image, final int x, final int y, final int newColor, final int oldColor) {
42+
if (image.length == 0 || image[0].length == 0 || newColor == oldColor || shouldSkipPixel(image, x, y, oldColor)) {
43+
return;
44+
}
45+
46+
Queue<Point> queue = new LinkedList<>();
47+
queue.add(new Point(x, y));
48+
49+
int[] dx = {0, 0, -1, 1, 1, -1, 1, -1};
50+
int[] dy = {-1, 1, 0, 0, -1, 1, 1, -1};
51+
52+
while (!queue.isEmpty()) {
53+
Point currPoint = queue.poll();
54+
55+
if (shouldSkipPixel(image, currPoint.x, currPoint.y, oldColor)) {
56+
continue;
57+
}
58+
59+
image[currPoint.x][currPoint.y] = newColor;
60+
61+
for (int i = 0; i < 8; i++) {
62+
int curX = currPoint.x + dx[i];
63+
int curY = currPoint.y + dy[i];
64+
65+
if (!shouldSkipPixel(image, curX, curY, oldColor)) {
66+
queue.add(new Point(curX, curY));
67+
}
68+
}
69+
}
70+
}
71+
72+
/**
73+
* Represents a point in 2D space with integer coordinates.
74+
*/
75+
private static class Point {
76+
final int x;
77+
final int y;
78+
79+
Point(final int x, final int y) {
80+
this.x = x;
81+
this.y = y;
82+
}
83+
}
84+
85+
/**
86+
* Checks if a pixel should be skipped during flood fill operation.
87+
*
88+
* @param image The image to get boundaries
89+
* @param x The x co-ordinate of pixel to check
90+
* @param y The y co-ordinate of pixel to check
91+
* @param oldColor The old color which is to be replaced in the image
92+
* @return {@code true} if pixel should be skipped, else {@code false}
93+
*/
94+
private static boolean shouldSkipPixel(final int[][] image, final int x, final int y, final int oldColor) {
95+
96+
if (x < 0 || x >= image.length || y < 0 || y >= image[0].length || image[x][y] != oldColor) {
97+
return true;
98+
}
99+
100+
return false;
101+
}
102+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.thealgorithms.maths;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
5+
6+
import java.util.stream.Stream;
7+
import org.junit.jupiter.api.DisplayName;
8+
import org.junit.jupiter.params.ParameterizedTest;
9+
import org.junit.jupiter.params.provider.Arguments;
10+
import org.junit.jupiter.params.provider.MethodSource;
11+
12+
class GermainPrimeAndSafePrimeTest {
13+
14+
static Stream<Arguments> provideNumbersForGermainPrimes() {
15+
return Stream.of(Arguments.of(2, Boolean.TRUE), Arguments.of(3, Boolean.TRUE), Arguments.of(5, Boolean.TRUE), Arguments.of(11, Boolean.TRUE), Arguments.of(23, Boolean.TRUE), Arguments.of(293, Boolean.TRUE), Arguments.of(4, Boolean.FALSE), Arguments.of(7, Boolean.FALSE),
16+
Arguments.of(9, Boolean.FALSE), Arguments.of(1, Boolean.FALSE));
17+
}
18+
19+
static Stream<Arguments> provideNumbersForSafePrimes() {
20+
return Stream.of(Arguments.of(5, Boolean.TRUE), Arguments.of(7, Boolean.TRUE), Arguments.of(11, Boolean.TRUE), Arguments.of(23, Boolean.TRUE), Arguments.of(1283, Boolean.TRUE), Arguments.of(4, Boolean.FALSE), Arguments.of(13, Boolean.FALSE), Arguments.of(9, Boolean.FALSE),
21+
Arguments.of(1, Boolean.FALSE));
22+
}
23+
24+
static Stream<Integer> provideNegativeNumbers() {
25+
return Stream.of(-10, -1, 0);
26+
}
27+
28+
@ParameterizedTest
29+
@MethodSource("provideNumbersForGermainPrimes")
30+
@DisplayName("Check whether a number is a Germain prime")
31+
void testValidGermainPrimes(int number, boolean expected) {
32+
assertEquals(expected, GermainPrimeAndSafePrime.isGermainPrime(number));
33+
}
34+
35+
@ParameterizedTest
36+
@MethodSource("provideNumbersForSafePrimes")
37+
@DisplayName("Check whether a number is a Safe prime")
38+
void testValidSafePrimes(int number, boolean expected) {
39+
assertEquals(expected, GermainPrimeAndSafePrime.isSafePrime(number));
40+
}
41+
42+
@ParameterizedTest
43+
@MethodSource("provideNegativeNumbers")
44+
@DisplayName("Negative numbers and zero should throw IllegalArgumentException")
45+
void testNegativeNumbersThrowException(int number) {
46+
assertThrows(IllegalArgumentException.class, () -> GermainPrimeAndSafePrime.isGermainPrime(number));
47+
assertThrows(IllegalArgumentException.class, () -> GermainPrimeAndSafePrime.isSafePrime(number));
48+
}
49+
}
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package com.thealgorithms.others;
2+
3+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
4+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
5+
6+
import org.junit.jupiter.api.Test;
7+
8+
class IterativeFloodFillTest {
9+
10+
@Test
11+
void testForEmptyImage() {
12+
int[][] image = {};
13+
int[][] expected = {};
14+
15+
IterativeFloodFill.floodFill(image, 4, 5, 3, 2);
16+
assertArrayEquals(expected, image);
17+
}
18+
19+
@Test
20+
void testForSingleElementImage() {
21+
int[][] image = {{1}};
22+
int[][] expected = {{3}};
23+
24+
IterativeFloodFill.floodFill(image, 0, 0, 3, 1);
25+
assertArrayEquals(expected, image);
26+
}
27+
28+
@Test
29+
void testForEmptyRow() {
30+
int[][] image = {{}};
31+
int[][] expected = {{}};
32+
33+
IterativeFloodFill.floodFill(image, 4, 5, 3, 2);
34+
assertArrayEquals(expected, image);
35+
}
36+
37+
@Test
38+
void testForImageOne() {
39+
int[][] image = {
40+
{0, 0, 0, 0, 0, 0, 0},
41+
{0, 3, 3, 3, 3, 0, 0},
42+
{0, 3, 1, 1, 5, 0, 0},
43+
{0, 3, 1, 1, 5, 5, 3},
44+
{0, 3, 5, 5, 1, 1, 3},
45+
{0, 0, 0, 5, 1, 1, 3},
46+
{0, 0, 0, 3, 3, 3, 3},
47+
};
48+
49+
int[][] expected = {
50+
{0, 0, 0, 0, 0, 0, 0},
51+
{0, 3, 3, 3, 3, 0, 0},
52+
{0, 3, 2, 2, 5, 0, 0},
53+
{0, 3, 2, 2, 5, 5, 3},
54+
{0, 3, 5, 5, 2, 2, 3},
55+
{0, 0, 0, 5, 2, 2, 3},
56+
{0, 0, 0, 3, 3, 3, 3},
57+
};
58+
59+
IterativeFloodFill.floodFill(image, 2, 2, 2, 1);
60+
assertArrayEquals(expected, image);
61+
}
62+
63+
@Test
64+
void testForImageTwo() {
65+
int[][] image = {
66+
{0, 0, 1, 1, 0, 0, 0},
67+
{1, 1, 3, 3, 3, 0, 0},
68+
{1, 3, 1, 1, 5, 0, 0},
69+
{0, 3, 1, 1, 5, 5, 3},
70+
{0, 3, 5, 5, 1, 1, 3},
71+
{0, 0, 0, 5, 1, 1, 3},
72+
{0, 0, 0, 1, 3, 1, 3},
73+
};
74+
75+
int[][] expected = {
76+
{0, 0, 2, 2, 0, 0, 0},
77+
{2, 2, 3, 3, 3, 0, 0},
78+
{2, 3, 2, 2, 5, 0, 0},
79+
{0, 3, 2, 2, 5, 5, 3},
80+
{0, 3, 5, 5, 2, 2, 3},
81+
{0, 0, 0, 5, 2, 2, 3},
82+
{0, 0, 0, 2, 3, 2, 3},
83+
};
84+
85+
IterativeFloodFill.floodFill(image, 2, 2, 2, 1);
86+
assertArrayEquals(expected, image);
87+
}
88+
89+
@Test
90+
void testForImageThree() {
91+
int[][] image = {
92+
{1, 1, 2, 3, 1, 1, 1},
93+
{1, 0, 0, 1, 0, 0, 1},
94+
{1, 1, 1, 0, 3, 1, 2},
95+
};
96+
97+
int[][] expected = {
98+
{4, 4, 2, 3, 4, 4, 4},
99+
{4, 0, 0, 4, 0, 0, 4},
100+
{4, 4, 4, 0, 3, 4, 2},
101+
};
102+
103+
IterativeFloodFill.floodFill(image, 0, 1, 4, 1);
104+
assertArrayEquals(expected, image);
105+
}
106+
107+
@Test
108+
void testForSameNewAndOldColor() {
109+
int[][] image = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
110+
111+
int[][] expected = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
112+
113+
IterativeFloodFill.floodFill(image, 0, 1, 1, 1);
114+
assertArrayEquals(expected, image);
115+
}
116+
117+
@Test
118+
void testForBigImage() {
119+
int[][] image = new int[100][100];
120+
121+
assertDoesNotThrow(() -> IterativeFloodFill.floodFill(image, 0, 0, 1, 0));
122+
}
123+
124+
@Test
125+
void testForBelowZeroX() {
126+
int[][] image = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
127+
128+
int[][] expected = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
129+
130+
IterativeFloodFill.floodFill(image, -1, 1, 1, 0);
131+
assertArrayEquals(expected, image);
132+
}
133+
134+
@Test
135+
void testForBelowZeroY() {
136+
int[][] image = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
137+
138+
int[][] expected = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
139+
140+
IterativeFloodFill.floodFill(image, 1, -1, 1, 0);
141+
assertArrayEquals(expected, image);
142+
}
143+
144+
@Test
145+
void testForAboveBoundaryX() {
146+
int[][] image = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
147+
148+
int[][] expected = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
149+
150+
IterativeFloodFill.floodFill(image, 100, 1, 1, 0);
151+
assertArrayEquals(expected, image);
152+
}
153+
154+
@Test
155+
void testForAboveBoundaryY() {
156+
int[][] image = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
157+
158+
int[][] expected = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
159+
160+
IterativeFloodFill.floodFill(image, 1, 100, 1, 0);
161+
assertArrayEquals(expected, image);
162+
}
163+
}

0 commit comments

Comments
 (0)