From 82ff14c36e80e975970dd61ac9fa193a192fa973 Mon Sep 17 00:00:00 2001 From: Yajunesh MR <145507360+Yajunesh@users.noreply.github.com> Date: Tue, 4 Nov 2025 02:42:24 +0530 Subject: [PATCH 01/74] feat: Add BitRotate utility for circular bit rotations (#7011) * feat: Add BitRotate utility for circular bit rotations * feat: Add BitRotate utility for circular bit rotations * feat: Add BitRotate utility for circular bit rotations * fix: Remove trailing spaces and add newline at EOF --------- Co-authored-by: Yajunesh M R --- .../bitmanipulation/BitRotate.java | 83 +++++++ .../bitmanipulation/BitRotateTest.java | 205 ++++++++++++++++++ 2 files changed, 288 insertions(+) create mode 100644 src/main/java/com/thealgorithms/bitmanipulation/BitRotate.java create mode 100644 src/test/java/com/thealgorithms/bitmanipulation/BitRotateTest.java diff --git a/src/main/java/com/thealgorithms/bitmanipulation/BitRotate.java b/src/main/java/com/thealgorithms/bitmanipulation/BitRotate.java new file mode 100644 index 000000000000..226e09e78d1f --- /dev/null +++ b/src/main/java/com/thealgorithms/bitmanipulation/BitRotate.java @@ -0,0 +1,83 @@ +package com.thealgorithms.bitmanipulation; + +/** + * Utility class for performing circular bit rotations on 32-bit integers. + * Bit rotation is a circular shift operation where bits shifted out on one end + * are reinserted on the opposite end. + * + *

This class provides methods for both left and right circular rotations, + * supporting only 32-bit integer operations with proper shift normalization + * and error handling.

+ * + * @see Bit Rotation + */ +public final class BitRotate { + + /** + * Private constructor to prevent instantiation. + * This is a utility class with only static methods. + */ + private BitRotate() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + + /** + * Performs a circular left rotation (left shift) on a 32-bit integer. + * Bits shifted out from the left side are inserted on the right side. + * + * @param value the 32-bit integer value to rotate + * @param shift the number of positions to rotate left (must be non-negative) + * @return the result of left rotating the value by the specified shift amount + * @throws IllegalArgumentException if shift is negative + * + * @example + * // Binary: 10000000 00000000 00000000 00000001 + * rotateLeft(0x80000001, 1) + * // Returns: 3 (binary: 00000000 00000000 00000000 00000011) + */ + public static int rotateLeft(int value, int shift) { + if (shift < 0) { + throw new IllegalArgumentException("Shift amount cannot be negative: " + shift); + } + + // Normalize shift to the range [0, 31] using modulo 32 + shift = shift % 32; + + if (shift == 0) { + return value; + } + + // Left rotation: (value << shift) | (value >>> (32 - shift)) + return (value << shift) | (value >>> (32 - shift)); + } + + /** + * Performs a circular right rotation (right shift) on a 32-bit integer. + * Bits shifted out from the right side are inserted on the left side. + * + * @param value the 32-bit integer value to rotate + * @param shift the number of positions to rotate right (must be non-negative) + * @return the result of right rotating the value by the specified shift amount + * @throws IllegalArgumentException if shift is negative + * + * @example + * // Binary: 00000000 00000000 00000000 00000011 + * rotateRight(3, 1) + * // Returns: -2147483647 (binary: 10000000 00000000 00000000 00000001) + */ + public static int rotateRight(int value, int shift) { + if (shift < 0) { + throw new IllegalArgumentException("Shift amount cannot be negative: " + shift); + } + + // Normalize shift to the range [0, 31] using modulo 32 + shift = shift % 32; + + if (shift == 0) { + return value; + } + + // Right rotation: (value >>> shift) | (value << (32 - shift)) + return (value >>> shift) | (value << (32 - shift)); + } +} diff --git a/src/test/java/com/thealgorithms/bitmanipulation/BitRotateTest.java b/src/test/java/com/thealgorithms/bitmanipulation/BitRotateTest.java new file mode 100644 index 000000000000..0595ae5a73e1 --- /dev/null +++ b/src/test/java/com/thealgorithms/bitmanipulation/BitRotateTest.java @@ -0,0 +1,205 @@ +package com.thealgorithms.bitmanipulation; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +/** + * Unit tests for BitRotate class covering typical, boundary, and edge cases. + * Tests verify correct behavior for 32-bit circular bit rotations. + * + * @author Yajunesh + */ +public class BitRotateTest { + + // ===== rotateLeft Tests ===== + + @Test + public void testRotateLeftBasic() { + // Basic left rotation + assertEquals(0b00000000_00000000_00000000_00000010, BitRotate.rotateLeft(1, 1)); + assertEquals(0b00000000_00000000_00000000_00000100, BitRotate.rotateLeft(1, 2)); + assertEquals(0b00000000_00000000_00000000_00001000, BitRotate.rotateLeft(1, 3)); + } + + @Test + public void testRotateLeftWithCarry() { + // Test bits carrying from left to right + // Binary: 10000000_00000000_00000000_00000001 + int value = 0x80000001; + // After left rotate by 1: 00000000_00000000_00000000_00000011 + assertEquals(3, BitRotate.rotateLeft(value, 1)); + + // Binary: 11000000_00000000_00000000_00000000 + value = 0xC0000000; + // After left rotate by 1: 10000000_00000000_00000000_00000001 + assertEquals(0x80000001, BitRotate.rotateLeft(value, 1)); + } + + @Test + public void testRotateLeftShift32() { + // Shift of 32 should be same as shift of 0 (modulo behavior) + int value = 0x12345678; + assertEquals(value, BitRotate.rotateLeft(value, 32)); + assertEquals(value, BitRotate.rotateLeft(value, 64)); + assertEquals(value, BitRotate.rotateLeft(value, 96)); + } + + @Test + public void testRotateLeftShiftNormalization() { + // Test that shifts > 32 are properly normalized + int value = 1; + assertEquals(BitRotate.rotateLeft(value, 1), BitRotate.rotateLeft(value, 33)); + assertEquals(BitRotate.rotateLeft(value, 5), BitRotate.rotateLeft(value, 37)); + } + + @Test + public void testRotateLeftZeroShift() { + // Zero shift should return original value + int value = 0xABCD1234; + assertEquals(value, BitRotate.rotateLeft(value, 0)); + } + + // ===== rotateRight Tests ===== + + @Test + public void testRotateRightBasic() { + // Basic right rotation + assertEquals(0b10000000_00000000_00000000_00000000, BitRotate.rotateRight(1, 1)); + assertEquals(0b01000000_00000000_00000000_00000000, BitRotate.rotateRight(1, 2)); + assertEquals(0b00100000_00000000_00000000_00000000, BitRotate.rotateRight(1, 3)); + } + + @Test + public void testRotateRightWithCarry() { + // Test bits carrying from right to left + // Binary: 00000000_00000000_00000000_00000011 + int value = 3; + // After right rotate by 1: 10000000_00000000_00000000_00000001 + assertEquals(0x80000001, BitRotate.rotateRight(value, 1)); + + // Binary: 00000000_00000000_00000000_00000001 + value = 1; + // After right rotate by 1: 10000000_00000000_00000000_00000000 + assertEquals(0x80000000, BitRotate.rotateRight(value, 1)); + } + + @Test + public void testRotateRightShift32() { + // Shift of 32 should be same as shift of 0 (modulo behavior) + int value = 0x9ABCDEF0; + assertEquals(value, BitRotate.rotateRight(value, 32)); + assertEquals(value, BitRotate.rotateRight(value, 64)); + assertEquals(value, BitRotate.rotateRight(value, 96)); + } + + @Test + public void testRotateRightShiftNormalization() { + // Test that shifts > 32 are properly normalized + int value = 1; + assertEquals(BitRotate.rotateRight(value, 1), BitRotate.rotateRight(value, 33)); + assertEquals(BitRotate.rotateRight(value, 7), BitRotate.rotateRight(value, 39)); + } + + @Test + public void testRotateRightZeroShift() { + // Zero shift should return original value + int value = 0xDEADBEEF; + assertEquals(value, BitRotate.rotateRight(value, 0)); + } + + // ===== Edge Case Tests ===== + + @Test + public void testRotateLeftMaxValue() { + // Test with maximum integer value + int value = Integer.MAX_VALUE; // 0x7FFFFFFF + int rotated = BitRotate.rotateLeft(value, 1); + // MAX_VALUE << 1 should become 0xFFFFFFFE, but with rotation it becomes different + assertEquals(0xFFFFFFFE, rotated); + } + + @Test + public void testRotateRightMinValue() { + // Test with minimum integer value (treated as unsigned) + int value = Integer.MIN_VALUE; // 0x80000000 + int rotated = BitRotate.rotateRight(value, 1); + // MIN_VALUE >>> 1 should become 0x40000000, but with rotation from left + assertEquals(0x40000000, rotated); + } + + @Test + public void testRotateAllOnes() { + // Test with all bits set + int value = 0xFFFFFFFF; // All ones + assertEquals(value, BitRotate.rotateLeft(value, 13)); + assertEquals(value, BitRotate.rotateRight(value, 27)); + } + + @Test + public void testRotateAllZeros() { + // Test with all bits zero + int value = 0x00000000; + assertEquals(value, BitRotate.rotateLeft(value, 15)); + assertEquals(value, BitRotate.rotateRight(value, 19)); + } + + // ===== Exception Tests ===== + + @Test + public void testRotateLeftNegativeShift() { + // Negative shifts should throw IllegalArgumentException + Exception exception = assertThrows(IllegalArgumentException.class, () -> BitRotate.rotateLeft(42, -1)); + assertTrue(exception.getMessage().contains("negative")); + } + + @Test + public void testRotateRightNegativeShift() { + // Negative shifts should throw IllegalArgumentException + Exception exception = assertThrows(IllegalArgumentException.class, () -> BitRotate.rotateRight(42, -5)); + assertTrue(exception.getMessage().contains("negative")); + } + + // ===== Complementary Operations Test ===== + + @Test + public void testRotateLeftRightComposition() { + // Rotating left then right by same amount should return original value + int original = 0x12345678; + int shift = 7; + + int leftRotated = BitRotate.rotateLeft(original, shift); + int restored = BitRotate.rotateRight(leftRotated, shift); + + assertEquals(original, restored); + } + + @Test + public void testRotateRightLeftComposition() { + // Rotating right then left by same amount should return original value + int original = 0x9ABCDEF0; + int shift = 13; + + int rightRotated = BitRotate.rotateRight(original, shift); + int restored = BitRotate.rotateLeft(rightRotated, shift); + + assertEquals(original, restored); + } + + @Test + public void testRotateLeft31IsSameAsRotateRight1() { + // Rotating left by 31 should be same as rotating right by 1 + int value = 0x55555555; + assertEquals(BitRotate.rotateLeft(value, 31), BitRotate.rotateRight(value, 1)); + } + + @Test + public void testTraversals() { + // Test that methods don't throw exceptions + assertDoesNotThrow(() -> BitRotate.rotateLeft(1, 1)); + assertDoesNotThrow(() -> BitRotate.rotateRight(1, 1)); + } +} From 100462d8e97295a5867a8efd6301bf45b19d80b9 Mon Sep 17 00:00:00 2001 From: Sourav Pati Date: Tue, 4 Nov 2025 02:59:44 +0530 Subject: [PATCH 02/74] Added LU Decomposition Algorithm for matrix (#6834) * Added LU decomposition algorthm * Added LU decomposition algorthim * Added LU decomposition algorthim * Added LU decomposition algorthim * Added LU decomposition algorthim * Added LU decomposition algorthim * Added LU decomposition algorthim * Added LU decomposition algorthim * Added LU decomposition algorthim --- .../thealgorithms/matrix/LUDecomposition.java | 88 +++++++++++++++++++ .../matrix/LUDecompositionTest.java | 40 +++++++++ 2 files changed, 128 insertions(+) create mode 100644 src/main/java/com/thealgorithms/matrix/LUDecomposition.java create mode 100644 src/test/java/com/thealgorithms/matrix/LUDecompositionTest.java diff --git a/src/main/java/com/thealgorithms/matrix/LUDecomposition.java b/src/main/java/com/thealgorithms/matrix/LUDecomposition.java new file mode 100644 index 000000000000..e41aaa201338 --- /dev/null +++ b/src/main/java/com/thealgorithms/matrix/LUDecomposition.java @@ -0,0 +1,88 @@ +package com.thealgorithms.matrix; + +/** + * LU Decomposition algorithm + * -------------------------- + * Decomposes a square matrix a into a product of two matrices: + * a = l * u + * where: + * - l is a lower triangular matrix with 1s on its diagonal + * - u is an upper triangular matrix + * + * Reference: + * https://en.wikipedia.org/wiki/lu_decomposition + */ +public final class LUDecomposition { + + private LUDecomposition() { + } + + /** + * A helper class to store both l and u matrices + */ + public static class LU { + double[][] l; + double[][] u; + + LU(double[][] l, double[][] u) { + this.l = l; + this.u = u; + } + } + + /** + * Performs LU Decomposition on a square matrix a + * + * @param a input square matrix + * @return LU object containing l and u matrices + */ + public static LU decompose(double[][] a) { + int n = a.length; + double[][] l = new double[n][n]; + double[][] u = new double[n][n]; + + for (int i = 0; i < n; i++) { + // upper triangular matrix + for (int k = i; k < n; k++) { + double sum = 0; + for (int j = 0; j < i; j++) { + sum += l[i][j] * u[j][k]; + } + u[i][k] = a[i][k] - sum; + } + + // lower triangular matrix + for (int k = i; k < n; k++) { + if (i == k) { + l[i][i] = 1; // diagonal as 1 + } else { + double sum = 0; + for (int j = 0; j < i; j++) { + sum += l[k][j] * u[j][i]; + } + l[k][i] = (a[k][i] - sum) / u[i][i]; + } + } + } + + return new LU(l, u); + } + + /** + * Utility function to print a matrix + * + * @param m matrix to print + */ + public static void printMatrix(double[][] m) { + for (double[] row : m) { + System.out.print("["); + for (int j = 0; j < row.length; j++) { + System.out.printf("%7.3f", row[j]); + if (j < row.length - 1) { + System.out.print(", "); + } + } + System.out.println("]"); + } + } +} diff --git a/src/test/java/com/thealgorithms/matrix/LUDecompositionTest.java b/src/test/java/com/thealgorithms/matrix/LUDecompositionTest.java new file mode 100644 index 000000000000..d3cc6d64bf42 --- /dev/null +++ b/src/test/java/com/thealgorithms/matrix/LUDecompositionTest.java @@ -0,0 +1,40 @@ +package com.thealgorithms.matrix; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import org.junit.jupiter.api.Test; + +public class LUDecompositionTest { + + @Test + public void testLUDecomposition() { + double[][] a = {{4, 3}, {6, 3}}; + + // Perform LU decomposition + LUDecomposition.LU lu = LUDecomposition.decompose(a); + double[][] l = lu.l; + double[][] u = lu.u; + + // Reconstruct a from l and u + double[][] reconstructed = multiplyMatrices(l, u); + + // Assert that reconstructed matrix matches original a + for (int i = 0; i < a.length; i++) { + assertArrayEquals(a[i], reconstructed[i], 1e-9); + } + } + + // Helper method to multiply two matrices + private double[][] multiplyMatrices(double[][] a, double[][] b) { + int n = a.length; + double[][] c = new double[n][n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + for (int k = 0; k < n; k++) { + c[i][j] += a[i][k] * b[k][j]; + } + } + } + return c; + } +} From f0a437d08cfd8b8542d26793ad884b3af4e06206 Mon Sep 17 00:00:00 2001 From: Deniz Altunkapan Date: Mon, 3 Nov 2025 23:26:10 +0100 Subject: [PATCH 03/74] Workflow/close failed prs (#6960) * chore: add workflow to close stale PRs with failed workflows * Include workflow failures when closing stale PRs * Filter meaningful commits to only include those within the last 14 days --- .github/workflows/close-failed-prs.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/close-failed-prs.yml b/.github/workflows/close-failed-prs.yml index f1bf3690f13f..6deea88f0daf 100644 --- a/.github/workflows/close-failed-prs.yml +++ b/.github/workflows/close-failed-prs.yml @@ -59,11 +59,13 @@ jobs: const meaningfulCommits = commits.filter(c => { const msg = c.commit.message.toLowerCase(); + const date = new Date(c.commit.committer.date); const isMergeFromMain = mainBranches.some(branch => msg.startsWith(`merge branch '${branch}'`) || msg.includes(`merge remote-tracking branch '${branch}'`) ); - return !isMergeFromMain; + + return !isMergeFromMain && date > cutoff; }); // Get checks with error handling @@ -151,4 +153,4 @@ jobs: } catch (error) { console.error(`❌ Fatal error: ${error.message}`); throw error; - } \ No newline at end of file + } From 5c965eb0977fbecb811e8f86d07a832bb75e3486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:09:05 +0700 Subject: [PATCH 04/74] chore: fix typos in src/test/java/com/thealgorithms/datastructures (#7045) Fix typos in src/test/java/com/thealgorithms/datastructures --- .../com/thealgorithms/datastructures/graphs/TwoSatTest.java | 2 +- .../datastructures/lists/SinglyLinkedListTest.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/TwoSatTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/TwoSatTest.java index 15e77b357f83..76b5aa8a780a 100644 --- a/src/test/java/com/thealgorithms/datastructures/graphs/TwoSatTest.java +++ b/src/test/java/com/thealgorithms/datastructures/graphs/TwoSatTest.java @@ -8,7 +8,7 @@ /** * Testcases for 2-SAT. - * Please note thea whlie checking for boolean assignments always keep n + 1 elements and the first element should be always false. + * Please note thea while checking for boolean assignments always keep n + 1 elements and the first element should be always false. */ public class TwoSatTest { private TwoSat twoSat; diff --git a/src/test/java/com/thealgorithms/datastructures/lists/SinglyLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/SinglyLinkedListTest.java index f80c6b5055f0..fde52b982385 100644 --- a/src/test/java/com/thealgorithms/datastructures/lists/SinglyLinkedListTest.java +++ b/src/test/java/com/thealgorithms/datastructures/lists/SinglyLinkedListTest.java @@ -214,10 +214,10 @@ void recursiveReverseListTest() { @Test void readWithEnhancedForLoopTest() { - final var expeced = new ArrayList(Arrays.asList(10, 20, 30)); + final var expected = new ArrayList(Arrays.asList(10, 20, 30)); SinglyLinkedList list = new SinglyLinkedList(); - for (final var x : expeced) { + for (final var x : expected) { list.insert(x); } @@ -226,7 +226,7 @@ void readWithEnhancedForLoopTest() { readElements.add(x); } - assertEquals(readElements, expeced); + assertEquals(readElements, expected); } @Test From 2ff284960aab62b5b8d307f074552881605f769f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:25:18 +0700 Subject: [PATCH 05/74] chore: fix typos in src/main/java/com/thealgorithms/strings/Pangram.java (#7044) Fix typos in src/main/java/com/thealgorithms/strings/Pangram.java Co-authored-by: a 19151554+alxkm@users.noreply.github.com --- src/main/java/com/thealgorithms/strings/Pangram.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/strings/Pangram.java b/src/main/java/com/thealgorithms/strings/Pangram.java index 01307b28f6c6..a92c282d7e52 100644 --- a/src/main/java/com/thealgorithms/strings/Pangram.java +++ b/src/main/java/com/thealgorithms/strings/Pangram.java @@ -60,7 +60,7 @@ public static boolean isPangram(String s) { } /** - * Checks if a String is Pangram or not by checking if each alhpabet is present or not + * Checks if a String is Pangram or not by checking if each alphabet is present or not * * @param s The String to check * @return {@code true} if s is a Pangram, otherwise {@code false} From c42e73bd95cacc76de971aabaf37fce94d3105d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:36:52 +0700 Subject: [PATCH 06/74] chore: fix typos in src/main/java/com/thealgorithms/others/MemoryManagementAlgorithms.java (#7043) Fix typos in src/main/java/com/thealgorithms/others/MemoryManagementAlgorithms.java Co-authored-by: a <19151554+alxkm@users.noreply.github.com> --- .../others/MemoryManagementAlgorithms.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/thealgorithms/others/MemoryManagementAlgorithms.java b/src/main/java/com/thealgorithms/others/MemoryManagementAlgorithms.java index 0924b8569942..40a5f6a7a767 100644 --- a/src/main/java/com/thealgorithms/others/MemoryManagementAlgorithms.java +++ b/src/main/java/com/thealgorithms/others/MemoryManagementAlgorithms.java @@ -16,7 +16,7 @@ public abstract class MemoryManagementAlgorithms { * blocks available. * @param sizeOfProcesses: an int array that contains the sizes of the * processes we need memory blocks for. - * @return the ArrayList filled with Integers repressenting the memory + * @return the ArrayList filled with Integers representing the memory * allocation that took place. */ public abstract ArrayList fitProcess(int[] sizeOfBlocks, int[] sizeOfProcesses); @@ -91,7 +91,7 @@ private static int findBestFit(int[] blockSizes, int processSize) { * blocks available. * @param sizeOfProcesses: an int array that contains the sizes of the * processes we need memory blocks for. - * @return the ArrayList filled with Integers repressenting the memory + * @return the ArrayList filled with Integers representing the memory * allocation that took place. */ public ArrayList fitProcess(int[] sizeOfBlocks, int[] sizeOfProcesses) { @@ -149,7 +149,7 @@ private static int findWorstFit(int[] blockSizes, int processSize) { * blocks available. * @param sizeOfProcesses: an int array that contains the sizes of the * processes we need memory blocks for. - * @return the ArrayList filled with Integers repressenting the memory + * @return the ArrayList filled with Integers representing the memory * allocation that took place. */ public ArrayList fitProcess(int[] sizeOfBlocks, int[] sizeOfProcesses) { @@ -201,7 +201,7 @@ private static int findFirstFit(int[] blockSizes, int processSize) { * blocks available. * @param sizeOfProcesses: an int array that contains the sizes of the * processes we need memory blocks for. - * @return the ArrayList filled with Integers repressenting the memory + * @return the ArrayList filled with Integers representing the memory * allocation that took place. */ public ArrayList fitProcess(int[] sizeOfBlocks, int[] sizeOfProcesses) { @@ -262,7 +262,7 @@ private int findNextFit(int[] blockSizes, int processSize) { * blocks available. * @param sizeOfProcesses: an int array that contains the sizes of the * processes we need memory blocks for. - * @return the ArrayList filled with Integers repressenting the memory + * @return the ArrayList filled with Integers representing the memory * allocation that took place. */ public ArrayList fitProcess(int[] sizeOfBlocks, int[] sizeOfProcesses) { From a3717f0563e819c85d369d502ff03a0769d37593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:43:02 +0700 Subject: [PATCH 07/74] chore: fix typos in src/main/java/com/thealgorithms/others/IterativeFloodFill.java (#7042) Fix typos in src/main/java/com/thealgorithms/others/IterativeFloodFill.java --- .../java/com/thealgorithms/others/IterativeFloodFill.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/thealgorithms/others/IterativeFloodFill.java b/src/main/java/com/thealgorithms/others/IterativeFloodFill.java index 3ef90369bd52..3f685f418a3d 100644 --- a/src/main/java/com/thealgorithms/others/IterativeFloodFill.java +++ b/src/main/java/com/thealgorithms/others/IterativeFloodFill.java @@ -32,8 +32,8 @@ private IterativeFloodFill() { * Iteratively fill the 2D image with new color * * @param image The image to be filled - * @param x The x co-ordinate at which color is to be filled - * @param y The y co-ordinate at which color is to be filled + * @param x The x coordinate at which color is to be filled + * @param y The y coordinate at which color is to be filled * @param newColor The new color which to be filled in the image * @param oldColor The old color which is to be replaced in the image * @see FloodFill BFS @@ -86,8 +86,8 @@ private static class Point { * Checks if a pixel should be skipped during flood fill operation. * * @param image The image to get boundaries - * @param x The x co-ordinate of pixel to check - * @param y The y co-ordinate of pixel to check + * @param x The x coordinate of pixel to check + * @param y The y coordinate of pixel to check * @param oldColor The old color which is to be replaced in the image * @return {@code true} if pixel should be skipped, else {@code false} */ From 08ee26f2b8bbff2f71086b7ddb57a9000783c289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:50:43 +0700 Subject: [PATCH 08/74] chore: fix typos in src/main/java/com/thealgorithms/others/Implementing_auto_completing_features_using_trie.java (#7041) Fix typos in src/main/java/com/thealgorithms/others/Implementing_auto_completing_features_using_trie.java --- .../Implementing_auto_completing_features_using_trie.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/others/Implementing_auto_completing_features_using_trie.java b/src/main/java/com/thealgorithms/others/Implementing_auto_completing_features_using_trie.java index bb88c7e3ae2f..7a1a7aadd805 100644 --- a/src/main/java/com/thealgorithms/others/Implementing_auto_completing_features_using_trie.java +++ b/src/main/java/com/thealgorithms/others/Implementing_auto_completing_features_using_trie.java @@ -97,7 +97,7 @@ static void suggestionsRec(TrieNode root, String currPrefix) { } } - // Fucntion to print suggestions for + // Function to print suggestions for // given query prefix. static int printAutoSuggestions(TrieNode root, final String query) { TrieNode pCrawl = root; From d92ab9d89ca296a700cb56909b987f61e03ff484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:56:34 +0700 Subject: [PATCH 09/74] chore: fix typos in src/main/java/com/thealgorithms/others/GaussLegendre.java (#7040) Fix typos in src/main/java/com/thealgorithms/others/GaussLegendre.java --- src/main/java/com/thealgorithms/others/GaussLegendre.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/others/GaussLegendre.java b/src/main/java/com/thealgorithms/others/GaussLegendre.java index b56b51f158fb..acf76ae3b192 100644 --- a/src/main/java/com/thealgorithms/others/GaussLegendre.java +++ b/src/main/java/com/thealgorithms/others/GaussLegendre.java @@ -1,7 +1,7 @@ package com.thealgorithms.others; /** - * Guass Legendre Algorithm ref + * Gauss Legendre Algorithm ref * https://en.wikipedia.org/wiki/Gauss–Legendre_algorithm * * @author AKS1996 From 26b47cb5b80c0faa9ead2460f2548b8cb32201dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:02:56 +0700 Subject: [PATCH 10/74] chore: fix typos in src/main/java/com/thealgorithms/others/BankersAlgorithm.java (#7039) Fix typos in src/main/java/com/thealgorithms/others/BankersAlgorithm.java --- src/main/java/com/thealgorithms/others/BankersAlgorithm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/others/BankersAlgorithm.java b/src/main/java/com/thealgorithms/others/BankersAlgorithm.java index 836526529374..5abf633a1c12 100644 --- a/src/main/java/com/thealgorithms/others/BankersAlgorithm.java +++ b/src/main/java/com/thealgorithms/others/BankersAlgorithm.java @@ -3,7 +3,7 @@ import java.util.Scanner; /** - * This file contains an implementation of BANKER'S ALGORITM Wikipedia: + * This file contains an implementation of BANKER'S ALGORITHM Wikipedia: * https://en.wikipedia.org/wiki/Banker%27s_algorithm * * The algorithm for finding out whether or not a system is in a safe state can From 3b14d6d3987e4f52c73c3372cedc89ddae9ed895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:13:26 +0700 Subject: [PATCH 11/74] chore: fix typos in src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java (#7038) Fix typos in src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java --- .../java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java b/src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java index 9a7f255282ac..7ee8a1a9f0ed 100644 --- a/src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java +++ b/src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java @@ -40,7 +40,7 @@ static void printMatrix(int[][] arr) { } /** - * Class containing the algo to roate matrix by 90 degree + * Class containing the algo to rotate matrix by 90 degree */ final class Rotate { private Rotate() { From 1645f31e790b6c3ae36ddae81b654e6e5fbc0960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:16:55 +0700 Subject: [PATCH 12/74] chore: fix typos in src/main/java/com/thealgorithms/maths/SieveOfAtkin.java (#7037) Fix typos in src/main/java/com/thealgorithms/maths/SieveOfAtkin.java Co-authored-by: a <19151554+alxkm@users.noreply.github.com> --- src/main/java/com/thealgorithms/maths/SieveOfAtkin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java b/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java index ee59d0784ec4..780dd81dac7c 100644 --- a/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java +++ b/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java @@ -14,7 +14,7 @@ public final class SieveOfAtkin { private SieveOfAtkin() { - // Utlity class; prevent instantiation + // Utility class; prevent instantiation } /** From f403ce66f9894b7c15e786dc468eb52ac2ade5f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:23:30 +0700 Subject: [PATCH 13/74] chore: fix typos in src/main/java/com/thealgorithms/maths/BinomialCoefficient.java (#7036) Fix typos in src/main/java/com/thealgorithms/maths/BinomialCoefficient.java Co-authored-by: a <19151554+alxkm@users.noreply.github.com> --- .../java/com/thealgorithms/maths/BinomialCoefficient.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/maths/BinomialCoefficient.java b/src/main/java/com/thealgorithms/maths/BinomialCoefficient.java index faec049b08a7..1de39adbc18a 100644 --- a/src/main/java/com/thealgorithms/maths/BinomialCoefficient.java +++ b/src/main/java/com/thealgorithms/maths/BinomialCoefficient.java @@ -1,8 +1,8 @@ package com.thealgorithms.maths; /* - * Java program for Binomial Cofficients - * Binomial Cofficients: A binomial cofficient C(n,k) gives number ways + * Java program for Binomial Coefficients + * Binomial Coefficients: A binomial coefficient C(n,k) gives number ways * in which k objects can be chosen from n objects. * Wikipedia: https://en.wikipedia.org/wiki/Binomial_coefficient * From 500c5264519a389e57e8c094c876e414cb49be7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:27:10 +0700 Subject: [PATCH 14/74] chore: fix typos in src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java (#7035) Fix typos in src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java --- .../com/thealgorithms/divideandconquer/SkylineAlgorithm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java b/src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java index 610b1b78a36a..0e8d9442138c 100644 --- a/src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java +++ b/src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java @@ -161,7 +161,7 @@ public int getY() { * function dominates the argument point. * * @param p1 the point that is compared - * @return true if the point wich calls the function dominates p1 false + * @return true if the point which calls the function dominates p1 false * otherwise. */ public boolean dominates(Point p1) { From 88c8e3935cf21dc97afc0298b519b0f19db3eeec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:31:34 +0700 Subject: [PATCH 15/74] chore: fix typos in src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java (#7034) Fix typos in src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java Co-authored-by: a <19151554+alxkm@users.noreply.github.com> --- .../java/com/thealgorithms/divideandconquer/ClosestPair.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java b/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java index cd26f9213651..4c9c40c83174 100644 --- a/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java +++ b/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java @@ -182,7 +182,7 @@ public double closestPair(final Location[] a, final int indexNum) { double minLeftArea; // Minimum length of left array double minRightArea; // Minimum length of right array - double minValue; // Minimum lengt + double minValue; // Minimum length minLeftArea = closestPair(leftArray, divideX); // recursive closestPair minRightArea = closestPair(rightArray, indexNum - divideX); From b87b1102d0f12219dc288707d6141b283839d676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:35:18 +0700 Subject: [PATCH 16/74] chore: fix typos in src/main/java/com/thealgorithms/datastructures/queues/PriorityQueues.java (#7028) Fix typos in src/main/java/com/thealgorithms/datastructures/queues/PriorityQueues.java Co-authored-by: a <19151554+alxkm@users.noreply.github.com> --- .../datastructures/queues/PriorityQueues.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/queues/PriorityQueues.java b/src/main/java/com/thealgorithms/datastructures/queues/PriorityQueues.java index a5ca48670f2c..b877a5843b98 100644 --- a/src/main/java/com/thealgorithms/datastructures/queues/PriorityQueues.java +++ b/src/main/java/com/thealgorithms/datastructures/queues/PriorityQueues.java @@ -9,7 +9,7 @@ * give numbers that are bigger, a higher priority. Queues in theory have no * fixed size but when using an array implementation it does. *

- * Additional contibutions made by: PuneetTri(https://github.com/PuneetTri) + * Additional contributions made by: PuneetTri(https://github.com/PuneetTri) */ class PriorityQueue { @@ -32,8 +32,8 @@ class PriorityQueue { PriorityQueue() { /* If capacity is not defined, default size of 11 would be used - * capacity=max+1 because we cant access 0th element of PQ, and to - * accomodate (max)th elements we need capacity to be max+1. + * capacity=max+1 because we can't access 0th element of PQ, and to + * accommodate (max)th elements we need capacity to be max+1. * Parent is at position k, child at position (k*2,k*2+1), if we * use position 0 in our queue, its child would be at: * (0*2, 0*2+1) -> (0,0). This is why we start at position 1 @@ -127,7 +127,7 @@ public int remove() { if (isEmpty()) { throw new RuntimeException("Queue is Empty"); } else { - int max = queueArray[1]; // By defintion of our max-heap, value at queueArray[1] pos is + int max = queueArray[1]; // By definition of our max-heap, value at queueArray[1] pos is // the greatest // Swap max and last element From 19f0f0bd83fb350004f375df180d3f65089013d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:40:08 +0700 Subject: [PATCH 17/74] chore: fix typos in src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java (#7024) Fix typos in src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java --- .../com/thealgorithms/conversions/TurkishToLatinConversion.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java b/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java index 30030de6c1bd..50726380621a 100644 --- a/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java +++ b/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java @@ -16,7 +16,7 @@ private TurkishToLatinConversion() { * 2. Replace all turkish characters with their corresponding latin characters * 3. Return the converted string * - * @param param String paramter + * @param param String parameter * @return String */ public static String convertTurkishToLatin(String param) { From dd01b35d973a7021b3d8a6a56cf9b21f61c49016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:44:45 +0700 Subject: [PATCH 18/74] chore: fix typos in src/main/java/com/thealgorithms/datastructures/graphs/BellmanFord.java (#7025) Fix typos in src/main/java/com/thealgorithms/datastructures/graphs/BellmanFord.java Co-authored-by: a <19151554+alxkm@users.noreply.github.com> --- .../com/thealgorithms/datastructures/graphs/BellmanFord.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/BellmanFord.java b/src/main/java/com/thealgorithms/datastructures/graphs/BellmanFord.java index 47c5f0d0b98e..5184dae58d28 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/BellmanFord.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/BellmanFord.java @@ -160,7 +160,7 @@ public void show(int source, int end, break; } } - if (neg == 0) { // Go ahead and show results of computaion + if (neg == 0) { // Go ahead and show results of computation System.out.println("Distance is: " + dist[end]); System.out.println("Path followed:"); System.out.print(source + " "); From fab09e7da17325a99ef9033d585f978e26867435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:48:33 +0700 Subject: [PATCH 19/74] chore: fix typos in src/main/java/com/thealgorithms/datastructures/graphs/MatrixGraphs.java (#7026) Fix typos in src/main/java/com/thealgorithms/datastructures/graphs/MatrixGraphs.java Co-authored-by: a <19151554+alxkm@users.noreply.github.com> --- .../com/thealgorithms/datastructures/graphs/MatrixGraphs.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/MatrixGraphs.java b/src/main/java/com/thealgorithms/datastructures/graphs/MatrixGraphs.java index c1d47df457da..a54b0b75e4dc 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/MatrixGraphs.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/MatrixGraphs.java @@ -141,7 +141,7 @@ private int[][] adjacency() { * * @param from the parent vertex to check for adjacency * @param to the child vertex to check for adjacency - * @return whether or not the vertices are adjancent + * @return whether or not the vertices are adjacent */ private boolean adjacencyOfEdgeDoesExist(int from, int to) { return (this.adjacency()[from][to] != AdjacencyMatrixGraph.EDGE_NONE); @@ -162,7 +162,7 @@ public boolean vertexDoesExist(int aVertex) { * * @param from the parent vertex to check for adjacency * @param to the child vertex to check for adjacency - * @return whether or not the vertices are adjancent + * @return whether or not the vertices are adjacent */ public boolean edgeDoesExist(int from, int to) { if (this.vertexDoesExist(from) && this.vertexDoesExist(to)) { From 8ae57476b1298601c37da6742bb85902f2ac9b95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:53:11 +0700 Subject: [PATCH 20/74] chore: fix typos in src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java (#7033) Fix typos in src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java --- src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java b/src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java index 13c9212306c1..1639bec6e5a0 100644 --- a/src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java +++ b/src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java @@ -12,7 +12,7 @@ public abstract class TreeNode extends Node { /** - * Refernce to the parent Node. + * Reference to the parent Node. */ private TreeNode parentNode; /** @@ -21,7 +21,7 @@ public abstract class TreeNode extends Node { private int depth; /** - * Empty contructor. + * Empty constructor. */ public TreeNode() { super(); From 96304bda3008db17c2dab589c6415f25eb7aba06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:56:44 +0700 Subject: [PATCH 21/74] chore: fix typos in src/main/java/com/thealgorithms/devutils/nodes/SimpleTreeNode.java (#7032) Fix typos in src/main/java/com/thealgorithms/devutils/nodes/SimpleTreeNode.java --- .../com/thealgorithms/devutils/nodes/SimpleTreeNode.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/thealgorithms/devutils/nodes/SimpleTreeNode.java b/src/main/java/com/thealgorithms/devutils/nodes/SimpleTreeNode.java index 215f01a6ef59..eefffacee8d6 100644 --- a/src/main/java/com/thealgorithms/devutils/nodes/SimpleTreeNode.java +++ b/src/main/java/com/thealgorithms/devutils/nodes/SimpleTreeNode.java @@ -11,16 +11,16 @@ public class SimpleTreeNode extends TreeNode { /** - * Refrence to the child Node on the left. + * Reference to the child Node on the left. */ private SimpleTreeNode leftNode; /** - * Refrence to the child Node on the right. + * Reference to the child Node on the right. */ private SimpleTreeNode rightNode; /** - * Empty contructor. + * Empty constructor. */ public SimpleTreeNode() { super(); From 65eeb5579e9a7c41a5037502b7d239e71e848ca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 18:01:44 +0700 Subject: [PATCH 22/74] chore: fix typos in src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java (#7031) Fix typos in src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java Co-authored-by: a <19151554+alxkm@users.noreply.github.com> --- src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java b/src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java index 769ffc2a9a96..bf3e795dd74b 100644 --- a/src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java +++ b/src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java @@ -15,7 +15,7 @@ public class SimpleNode extends Node { private SimpleNode nextNode; /** - * Empty contructor. + * Empty constructor. */ public SimpleNode() { super(); From d75a66887033913b798be4a720f2b2b998f4f078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 18:05:13 +0700 Subject: [PATCH 23/74] chore: fix typos in src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java (#7030) Fix typos in src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java --- .../thealgorithms/datastructures/trees/BSTRecursiveGeneric.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java b/src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java index 0245372fe012..2c94224ddeb4 100644 --- a/src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java +++ b/src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java @@ -30,7 +30,7 @@ public BSTRecursiveGeneric() { } /** - * Displays the tree is a structed format + * Displays the tree is a structured format */ public void prettyDisplay() { prettyDisplay(root, 0); From 0c277a1d9e1be23df1a0063ed5524f9640c15258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 18:08:49 +0700 Subject: [PATCH 24/74] chore: fix typos in src/main/java/com/thealgorithms/datastructures/heaps/FibonacciHeap.java (#7027) Fix typos in src/main/java/com/thealgorithms/datastructures/heaps/FibonacciHeap.java --- .../com/thealgorithms/datastructures/heaps/FibonacciHeap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/datastructures/heaps/FibonacciHeap.java b/src/main/java/com/thealgorithms/datastructures/heaps/FibonacciHeap.java index 7a263fc08ac5..834de9c77881 100644 --- a/src/main/java/com/thealgorithms/datastructures/heaps/FibonacciHeap.java +++ b/src/main/java/com/thealgorithms/datastructures/heaps/FibonacciHeap.java @@ -387,7 +387,7 @@ public class HeapNode { private HeapNode parent; /* - * a constructor for a heapNode withe key @param (key) + * a constructor for a heapNode with key @param (key) * prev == next == this * parent == child == null */ From 8c8527c2c8a8b68033937b565029bc36e15f1b7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 18:12:14 +0700 Subject: [PATCH 25/74] chore: fix typos in src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java (#7029) Fix typos in src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java --- .../java/com/thealgorithms/datastructures/trees/AVLSimple.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java b/src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java index e0309122cc12..07fc5c87b6c4 100644 --- a/src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java +++ b/src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java @@ -1,7 +1,7 @@ package com.thealgorithms.datastructures.trees; /* -* Avl is algo that balance itself while adding new alues to tree +* Avl is algo that balance itself while adding new values to tree * by rotating branches of binary tree and make itself Binary seaarch tree * there are four cases which has to tackle * rotating - left right ,left left,right right,right left From 53230842f2e8bdff9cc7363b876a45a2de151bf6 Mon Sep 17 00:00:00 2001 From: Avaneeshakrishna <36323856+Avaneeshakrishna@users.noreply.github.com> Date: Wed, 5 Nov 2025 03:22:39 -0800 Subject: [PATCH 26/74] add CombinationSum and test (#6725) * add CombinationSum and test * Format array and list literals in CombinationSumTest * Fix sorting comparator in CombinationSumTest * Refactor CombinationSum for better handling and clarity Updated combinationSum method to handle null or empty candidates and improved variable naming for clarity. * Fix sorting comparator in CombinationSumTest * Update CombinationSumTest.java * Fix sorting comparator for list of integers * Fix formatting issues in CombinationSum class * Change CombinationSum class to final * Refactor norm method to accept Iterable instead of List * Remove unnecessary whitespace in CombinationSumTest --- .../backtracking/CombinationSum.java | 48 +++++++++++++++++++ .../backtracking/CombinationSumTest.java | 29 +++++++++++ 2 files changed, 77 insertions(+) create mode 100644 src/main/java/com/thealgorithms/backtracking/CombinationSum.java create mode 100644 src/test/java/com/thealgorithms/backtracking/CombinationSumTest.java diff --git a/src/main/java/com/thealgorithms/backtracking/CombinationSum.java b/src/main/java/com/thealgorithms/backtracking/CombinationSum.java new file mode 100644 index 000000000000..09b99032bdc1 --- /dev/null +++ b/src/main/java/com/thealgorithms/backtracking/CombinationSum.java @@ -0,0 +1,48 @@ +package com.thealgorithms.backtracking; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** Backtracking: pick/not-pick with reuse of candidates. */ +public final class CombinationSum { + private CombinationSum() { + throw new UnsupportedOperationException("Utility class"); + } + + public static List> combinationSum(int[] candidates, int target) { + List> results = new ArrayList<>(); + if (candidates == null || candidates.length == 0) { + return results; + } + + // Sort to help with pruning duplicates and early termination + Arrays.sort(candidates); + backtrack(candidates, target, 0, new ArrayList<>(), results); + return results; + } + + private static void backtrack(int[] candidates, int remaining, int start, List combination, List> results) { + if (remaining == 0) { + // Found valid combination; add a copy + results.add(new ArrayList<>(combination)); + return; + } + + for (int i = start; i < candidates.length; i++) { + int candidate = candidates[i]; + + // If candidate is greater than remaining target, further candidates (sorted) will also be too big + if (candidate > remaining) { + break; + } + + // include candidate + combination.add(candidate); + // Because we can reuse the same element, we pass i (not i + 1) + backtrack(candidates, remaining - candidate, i, combination, results); + // backtrack: remove last + combination.remove(combination.size() - 1); + } + } +} diff --git a/src/test/java/com/thealgorithms/backtracking/CombinationSumTest.java b/src/test/java/com/thealgorithms/backtracking/CombinationSumTest.java new file mode 100644 index 000000000000..986c71acebe8 --- /dev/null +++ b/src/test/java/com/thealgorithms/backtracking/CombinationSumTest.java @@ -0,0 +1,29 @@ +package com.thealgorithms.backtracking; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import org.junit.jupiter.api.Test; + +class CombinationSumTest { + private static List> norm(Iterable> x) { + List> y = new ArrayList<>(); + for (var p : x) { + var q = new ArrayList<>(p); + q.sort(Integer::compare); + y.add(q); + } + y.sort(Comparator.>comparingInt(List::size).thenComparing(Object::toString)); + return y; + } + + @Test + void sample() { + int[] candidates = {2, 3, 6, 7}; + int target = 7; + var expected = List.of(List.of(2, 2, 3), List.of(7)); + assertEquals(norm(expected), norm(CombinationSum.combinationSum(candidates, target))); + } +} From 702664116d73dd8283c307bec606b6a31bdb70c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 22:41:33 +0700 Subject: [PATCH 27/74] chore: fix typos in src/main/java/com/thealgorithms/backtracking/FloodFill.java (#7046) Fix typos in src/main/java/com/thealgorithms/backtracking/FloodFill.java --- .../com/thealgorithms/backtracking/FloodFill.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/thealgorithms/backtracking/FloodFill.java b/src/main/java/com/thealgorithms/backtracking/FloodFill.java index c8219ca8ba7e..0f31a9c5a30e 100644 --- a/src/main/java/com/thealgorithms/backtracking/FloodFill.java +++ b/src/main/java/com/thealgorithms/backtracking/FloodFill.java @@ -12,8 +12,8 @@ private FloodFill() { * Get the color at the given coordinates of a 2D image * * @param image The image to be filled - * @param x The x co-ordinate of which color is to be obtained - * @param y The y co-ordinate of which color is to be obtained + * @param x The x coordinate of which color is to be obtained + * @param y The y coordinate of which color is to be obtained */ public static int getPixel(final int[][] image, final int x, final int y) { @@ -24,8 +24,8 @@ public static int getPixel(final int[][] image, final int x, final int y) { * Put the color at the given coordinates of a 2D image * * @param image The image to be filled - * @param x The x co-ordinate at which color is to be filled - * @param y The y co-ordinate at which color is to be filled + * @param x The x coordinate at which color is to be filled + * @param y The y coordinate at which color is to be filled */ public static void putPixel(final int[][] image, final int x, final int y, final int newColor) { image[x][y] = newColor; @@ -35,8 +35,8 @@ public static void putPixel(final int[][] image, final int x, final int y, final * Fill the 2D image with new color * * @param image The image to be filled - * @param x The x co-ordinate at which color is to be filled - * @param y The y co-ordinate at which color is to be filled + * @param x The x coordinate at which color is to be filled + * @param y The y coordinate at which color is to be filled * @param newColor The new color which to be filled in the image * @param oldColor The old color which is to be replaced in the image */ From 147da38888303b195c8d95a6f86dacfec9c5f665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 22:45:27 +0700 Subject: [PATCH 28/74] chore: fix typos in src/main/java/com/thealgorithms/ciphers/AES.java (#7047) Fix typos in src/main/java/com/thealgorithms/ciphers/AES.java Co-authored-by: Deniz Altunkapan --- src/main/java/com/thealgorithms/ciphers/AES.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/ciphers/AES.java b/src/main/java/com/thealgorithms/ciphers/AES.java index 1c283f6b7655..df51eba55310 100644 --- a/src/main/java/com/thealgorithms/ciphers/AES.java +++ b/src/main/java/com/thealgorithms/ciphers/AES.java @@ -2738,7 +2738,7 @@ public static BigInteger decrypt(BigInteger cipherText, BigInteger key) { public static void main(String[] args) { try (Scanner input = new Scanner(System.in)) { - System.out.println("Enter (e) letter for encrpyt or (d) letter for decrypt :"); + System.out.println("Enter (e) letter for encrypt or (d) letter for decrypt :"); char choice = input.nextLine().charAt(0); String in; switch (choice) { From c7cb54ed84f98e0d130caf3b4335c9eed69101d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 22:49:00 +0700 Subject: [PATCH 29/74] chore: fix typos in src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.java (#7048) Fix typos in src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.java --- .../datastructures/trees/CeilInBinarySearchTree.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.java b/src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.java index 214e111b9f1a..fff84111663b 100644 --- a/src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.java +++ b/src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.java @@ -21,7 +21,7 @@ * * Solution 1: Brute Force Solution: Do an inorder traversal and save result * into an array. Iterate over the array to get an element equal to or greater - * than current key. Time Complexity: O(n) Space Complexity: O(n) for auxillary + * than current key. Time Complexity: O(n) Space Complexity: O(n) for auxiliary * array to save inorder representation of tree. *

*

@@ -29,7 +29,7 @@ * into an array.Since array is sorted do a binary search over the array to get * an element equal to or greater than current key. Time Complexity: O(n) for * traversal of tree and O(lg(n)) for binary search in array. Total = O(n) Space - * Complexity: O(n) for auxillary array to save inorder representation of tree. + * Complexity: O(n) for auxiliary array to save inorder representation of tree. *

*

* Solution 3: Optimal We can do a DFS search on given tree in following From d28fee96650f9a295708d813b2c135081bbfc6b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Wed, 5 Nov 2025 22:53:18 +0700 Subject: [PATCH 30/74] chore: fix typos in src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java (#7049) Fix typos in src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java --- .../dynamicprogramming/BoundaryFill.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java b/src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java index 8494492f293f..ccd54ee4349a 100644 --- a/src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java +++ b/src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java @@ -12,8 +12,8 @@ private BoundaryFill() { * Get the color at the given co-odrinates of a 2D image * * @param image The image to be filled - * @param xCoordinate The x co-ordinate of which color is to be obtained - * @param yCoordinate The y co-ordinate of which color is to be obtained + * @param xCoordinate The x coordinate of which color is to be obtained + * @param yCoordinate The y coordinate of which color is to be obtained */ public static int getPixel(int[][] image, int xCoordinate, int yCoordinate) { return image[xCoordinate][yCoordinate]; @@ -23,8 +23,8 @@ public static int getPixel(int[][] image, int xCoordinate, int yCoordinate) { * Put the color at the given co-odrinates of a 2D image * * @param image The image to be filed - * @param xCoordinate The x co-ordinate at which color is to be filled - * @param yCoordinate The y co-ordinate at which color is to be filled + * @param xCoordinate The x coordinate at which color is to be filled + * @param yCoordinate The y coordinate at which color is to be filled */ public static void putPixel(int[][] image, int xCoordinate, int yCoordinate, int newColor) { image[xCoordinate][yCoordinate] = newColor; @@ -34,8 +34,8 @@ public static void putPixel(int[][] image, int xCoordinate, int yCoordinate, int * Fill the 2D image with new color * * @param image The image to be filed - * @param xCoordinate The x co-ordinate at which color is to be filled - * @param yCoordinate The y co-ordinate at which color is to be filled + * @param xCoordinate The x coordinate at which color is to be filled + * @param yCoordinate The y coordinate at which color is to be filled * @param newColor The new color which to be filled in the image * @param boundaryColor The old color which is to be replaced in the image */ From d126fd59f7c4f9aac8de23db2766bc6f6121394d Mon Sep 17 00:00:00 2001 From: Arzoo1701 <122432635+Arzoo1701@users.noreply.github.com> Date: Wed, 5 Nov 2025 23:11:08 +0530 Subject: [PATCH 31/74] Add Trapping Rainwater problem implementation (Two Pointer Approach) (#6990) * Add Trapping Rainwater problem implementation (Two Pointer Approach) * Add Wikipedia reference link for Trapping Rainwater problem * fix: format TrappingRainwater.java for CI check * fix: add package and resolve checkstyle errors for TrappingRainwater.java * fix: declare TrappingRainwater as final to pass Checkstyle * Add test cases for TrappingRainwater algorithm * Add test cases for TrappingRainwater algorithm * Move TrappingRainwater algorithm to stacks package * Fix: Move TrappingRainwater to stacks and normalize newline in JugglerSequence * Fix: Normalize newline in JugglerSequence to ensure test consistency * Fix: Normalize newline in JugglerSequence and remove return statement * Add JaCoCo plugin for code coverage reporting * Revert pom.xml to original version from master * Fix: Revert the pom.xml file --------- Co-authored-by: Deniz Altunkapan --- pom.xml | 2 +- .../stacks/TrappingRainwater.java | 48 +++++++++++++++++++ .../stacks/TrappingRainwaterTest.java | 38 +++++++++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/thealgorithms/stacks/TrappingRainwater.java create mode 100644 src/test/java/com/thealgorithms/stacks/TrappingRainwaterTest.java diff --git a/pom.xml b/pom.xml index 825d86f8b239..7e936967208b 100644 --- a/pom.xml +++ b/pom.xml @@ -155,4 +155,4 @@ - + \ No newline at end of file diff --git a/src/main/java/com/thealgorithms/stacks/TrappingRainwater.java b/src/main/java/com/thealgorithms/stacks/TrappingRainwater.java new file mode 100644 index 000000000000..072665061b8e --- /dev/null +++ b/src/main/java/com/thealgorithms/stacks/TrappingRainwater.java @@ -0,0 +1,48 @@ +package com.thealgorithms.stacks; +/** + * Trapping Rainwater Problem + * Given an array of non-negative integers representing the height of bars, + * compute how much water it can trap after raining. + * + * Example: + * Input: [4,2,0,3,2,5] + * Output: 9 + * + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * Reference: https://en.wikipedia.org/wiki/Trapping_rain_water + */ +public final class TrappingRainwater { + + private TrappingRainwater() { + throw new UnsupportedOperationException("Utility class"); + } + + public static int trap(int[] height) { + int left = 0; + int right = height.length - 1; + int leftMax = 0; + int rightMax = 0; + int result = 0; + + while (left < right) { + if (height[left] < height[right]) { + if (height[left] >= leftMax) { + leftMax = height[left]; + } else { + result += leftMax - height[left]; + } + left++; + } else { + if (height[right] >= rightMax) { + rightMax = height[right]; + } else { + result += rightMax - height[right]; + } + right--; + } + } + return result; + } +} diff --git a/src/test/java/com/thealgorithms/stacks/TrappingRainwaterTest.java b/src/test/java/com/thealgorithms/stacks/TrappingRainwaterTest.java new file mode 100644 index 000000000000..909be6cd46da --- /dev/null +++ b/src/test/java/com/thealgorithms/stacks/TrappingRainwaterTest.java @@ -0,0 +1,38 @@ +package com.thealgorithms.stacks; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class TrappingRainwaterTest { + + @Test + public void testExampleCase() { + int[] height = {4, 2, 0, 3, 2, 5}; + assertEquals(9, TrappingRainwater.trap(height)); + } + + @Test + public void testNoTrapping() { + int[] height = {1, 2, 3, 4, 5}; + assertEquals(0, TrappingRainwater.trap(height)); + } + + @Test + public void testFlatSurface() { + int[] height = {0, 0, 0, 0}; + assertEquals(0, TrappingRainwater.trap(height)); + } + + @Test + public void testSymmetricPit() { + int[] height = {3, 0, 2, 0, 3}; + assertEquals(7, TrappingRainwater.trap(height)); + } + + @Test + public void testSingleBar() { + int[] height = {5}; + assertEquals(0, TrappingRainwater.trap(height)); + } +} From 5a68ba93998c1ec4d0a201aba7e3d0ed942ae4c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Thu, 6 Nov 2025 17:40:34 +0700 Subject: [PATCH 32/74] chore: fix typos in some files (#7052) Fix typos in some files --- .../java/com/thealgorithms/datastructures/lists/README.md | 2 +- .../java/com/thealgorithms/devutils/nodes/LargeTreeNode.java | 4 ++-- src/main/java/com/thealgorithms/others/CRCAlgorithm.java | 4 ++-- .../searches/RowColumnWiseSorted2dArrayBinarySearch.java | 2 +- src/main/java/com/thealgorithms/sorts/LinkListSort.java | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/lists/README.md b/src/main/java/com/thealgorithms/datastructures/lists/README.md index 5a19c3bfa990..5a0a43b923e1 100644 --- a/src/main/java/com/thealgorithms/datastructures/lists/README.md +++ b/src/main/java/com/thealgorithms/datastructures/lists/README.md @@ -28,6 +28,6 @@ The `next` variable points to the next node in the data structure and value stor 4. `CreateAndDetectLoop.java` : Create and detect a loop in a linked list. 5. `DoublyLinkedList.java` : A modification of singly linked list which has a `prev` pointer to point to the previous node. 6. `MergeKSortedLinkedlist.java` : Merges K sorted linked list with mergesort (mergesort is also the most efficient sorting algorithm for linked list). -7. `RandomNode.java` : Selects a random node from given linked list and diplays it. +7. `RandomNode.java` : Selects a random node from given linked list and displays it. 8. `SkipList.java` : Data Structure used for storing a sorted list of elements with help of a Linked list hierarchy that connects to subsequences of elements. 9. `TortoiseHareAlgo.java` : Finds the middle element of a linked list using the fast and slow pointer (Tortoise-Hare) algorithm. diff --git a/src/main/java/com/thealgorithms/devutils/nodes/LargeTreeNode.java b/src/main/java/com/thealgorithms/devutils/nodes/LargeTreeNode.java index 95d53ecb1f7a..d69288f72200 100644 --- a/src/main/java/com/thealgorithms/devutils/nodes/LargeTreeNode.java +++ b/src/main/java/com/thealgorithms/devutils/nodes/LargeTreeNode.java @@ -3,7 +3,7 @@ import java.util.Collection; /** - * {@link TreeNode} extension that holds a {@link Collection} of refrences to + * {@link TreeNode} extension that holds a {@link Collection} of references to * child Nodes. * * @param The type of the data held in the Node. @@ -18,7 +18,7 @@ public class LargeTreeNode extends TreeNode { private Collection> childNodes; /** - * Empty contructor. + * Empty constructor. */ public LargeTreeNode() { super(); diff --git a/src/main/java/com/thealgorithms/others/CRCAlgorithm.java b/src/main/java/com/thealgorithms/others/CRCAlgorithm.java index 00ddc86be820..2d0be15e0a7b 100644 --- a/src/main/java/com/thealgorithms/others/CRCAlgorithm.java +++ b/src/main/java/com/thealgorithms/others/CRCAlgorithm.java @@ -95,7 +95,7 @@ public int getCorrectMess() { /** * Resets some of the object's values, used on the main function, so that it - * can be re-used, in order not to waste too much memory and time, by + * can be reused, in order not to waste too much memory and time, by * creating new objects. */ public void refactor() { @@ -171,7 +171,7 @@ public void divideMessageWithP(boolean check) { * Once the message is transmitted, some of it's elements, is possible to * change from 1 to 0, or from 0 to 1, because of the Bit Error Rate (ber). * For every element of the message, a random double number is created. If - * that number is smaller than ber, then the spesific element changes. On + * that number is smaller than ber, then the specific element changes. On * the other hand, if it's bigger than ber, it does not. Based on these * changes. the boolean variable messageChanged, gets the value: true, or * false. diff --git a/src/main/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearch.java b/src/main/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearch.java index b40c7554d84b..ecdcd36adf21 100644 --- a/src/main/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearch.java +++ b/src/main/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearch.java @@ -13,7 +13,7 @@ * In this two pointers are taken, the first points to the 0th row and the second one points to end * column, and then the element corresponding to the pointers placed in the array is compared with * the target that either its equal, greater or smaller than the target. If the element is equal to - * the target, the co-ordinates of that element is returned i.e. an array of the two pointers will + * the target, the coordinates of that element is returned i.e. an array of the two pointers will * be returned, else if the target is greater than corresponding element then the pointer pointing * to the 0th row will be incremented by 1, else if the target is lesser than the corresponding * element then the pointer pointing to the end column will be decremented by 1. And if the element diff --git a/src/main/java/com/thealgorithms/sorts/LinkListSort.java b/src/main/java/com/thealgorithms/sorts/LinkListSort.java index 800d78f36549..d8fd76a86236 100644 --- a/src/main/java/com/thealgorithms/sorts/LinkListSort.java +++ b/src/main/java/com/thealgorithms/sorts/LinkListSort.java @@ -106,7 +106,7 @@ public static boolean isSorted(int[] p, int option) { // The given array and the expected array is checked if both are same then true // is displayed else false is displayed default: - // default is used incase user puts a unauthorized value + // default is used in case user puts a unauthorized value System.out.println("Wrong choice"); } // Switch case is used to call the classes as per the user requirement From 4951fb9ce23005150c0f32c3eadb615f1e96bbab Mon Sep 17 00:00:00 2001 From: Priyanshu Kumar Singh Date: Thu, 6 Nov 2025 23:11:39 +0530 Subject: [PATCH 33/74] [FEAT] Add Kinematics (SUVAT) equations (#7053) [FEAT] Add SUVAT equation for motion Co-authored-by: Priyanshu1303d --- .../com/thealgorithms/physics/Kinematics.java | 69 +++++++++++++++++++ .../thealgorithms/physics/KinematicsTest.java | 48 +++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 src/main/java/com/thealgorithms/physics/Kinematics.java create mode 100644 src/test/java/com/thealgorithms/physics/KinematicsTest.java diff --git a/src/main/java/com/thealgorithms/physics/Kinematics.java b/src/main/java/com/thealgorithms/physics/Kinematics.java new file mode 100644 index 000000000000..d017fe787afd --- /dev/null +++ b/src/main/java/com/thealgorithms/physics/Kinematics.java @@ -0,0 +1,69 @@ +package com.thealgorithms.physics; +/** + * Implements the fundamental "SUVAT" equations for motion + * under constant acceleration. + * + * @author [Priyanshu Kumar Singh](https://github.com/Priyanshu1303d) + * @see Wikipedia + */ +public final class Kinematics { + private Kinematics() { + } + + /** + * Calculates the final velocity (v) of an object. + * Formula: v = u + at + * + * @param u Initial velocity (m/s). + * @param a Constant acceleration (m/s^2). + * @param t Time elapsed (s). + * @return The final velocity (m/s). + */ + + public static double calculateFinalVelocity(double u, double a, double t) { + return u + a * t; + } + + /** + * Calculates the displacement (s) of an object. + * Formula: s = ut + 0.5 * a * t^2 + * + * @param u Initial velocity (m/s). + * @param a Constant acceleration (m/s^2). + * @param t Time elapsed (s). + * @return The displacement (m). + */ + + public static double calculateDisplacement(double u, double a, double t) { + return u * t + 0.5 * a * t * t; + } + + /** + * Calculates the displacement (s) of an object. + * Formula: v^2 = u^2 + 2 * a * s + * + * @param u Initial velocity (m/s). + * @param a Constant acceleration (m/s^2). + * @param s Displacement (m). + * @return The final velocity squared (m/s)^2. + */ + + public static double calculateFinalVelocitySquared(double u, double a, double s) { + return u * u + 2 * a * s; + } + + /** + * Calculates the displacement (s) using the average velocity. + * Formula: s = (u + v) / 2 * t + * + * @param u Initial velocity (m/s). + * @param v Final velocity (m/s). + * @param t Time elapsed (s). + * @return The displacement (m). + */ + + public static double calculateDisplacementFromVelocities(double u, double v, double t) { + double velocitySum = u + v; + return velocitySum / 2 * t; + } +} diff --git a/src/test/java/com/thealgorithms/physics/KinematicsTest.java b/src/test/java/com/thealgorithms/physics/KinematicsTest.java new file mode 100644 index 000000000000..c5274b0814a7 --- /dev/null +++ b/src/test/java/com/thealgorithms/physics/KinematicsTest.java @@ -0,0 +1,48 @@ +package com.thealgorithms.physics; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for the Kinematics utility class. + */ + +public final class KinematicsTest { + // A small tolerance for comparing floating-point numbers + private static final double DELTA = 1e-9; + @Test + @DisplayName("Test final velocity: v = u + at") + void testCalculateFinalVelocity() { + assertEquals(20.0, Kinematics.calculateFinalVelocity(10.0, 2.0, 5.0), DELTA); + } + + @Test + @DisplayName("Test displacement: s = ut + 0.5at^2") + void testCalculateDisplacement() { + assertEquals(75.0, Kinematics.calculateDisplacement(10.0, 2.0, 5.0), DELTA); + } + + @Test + @DisplayName("Test final velocity squared: v^2 = u^2 + 2as") + void testCalculateFinalVelocitySquared() { + assertEquals(400.0, Kinematics.calculateFinalVelocitySquared(10.0, 2.0, 75.0), DELTA); + } + + @Test + @DisplayName("Test displacement from average velocity: s = (u+v)/2 * t") + void testCalculateDisplacementFromVelocities() { + assertEquals(75.0, Kinematics.calculateDisplacementFromVelocities(10.0, 20.0, 5.0), DELTA); + } + + @Test + @DisplayName("Test with negative acceleration (deceleration)") + void testDeceleration() { + assertEquals(10.0, Kinematics.calculateFinalVelocity(30.0, -4.0, 5.0), DELTA); + assertEquals(100.0, Kinematics.calculateDisplacement(30.0, -4.0, 5.0), DELTA); + + assertEquals(100.0, Kinematics.calculateFinalVelocitySquared(30.0, -4.0, 100.0), DELTA); + assertEquals(100.0, Kinematics.calculateDisplacementFromVelocities(30.0, 10.0, 5.0), DELTA); + } +} From 2588af02057eff98541d859a9a90f30b91268457 Mon Sep 17 00:00:00 2001 From: PRINCE PATEL Date: Fri, 7 Nov 2025 16:02:18 +0530 Subject: [PATCH 34/74] fix: Correct typo in ExponentialSearch filename (#7056) --- .../searches/{ExponentalSearch.java => ExponentialSearch.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/com/thealgorithms/searches/{ExponentalSearch.java => ExponentialSearch.java} (100%) diff --git a/src/main/java/com/thealgorithms/searches/ExponentalSearch.java b/src/main/java/com/thealgorithms/searches/ExponentialSearch.java similarity index 100% rename from src/main/java/com/thealgorithms/searches/ExponentalSearch.java rename to src/main/java/com/thealgorithms/searches/ExponentialSearch.java From 0a5516569231f5c6daa48f9397447cf063c3d6ec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 13:03:51 +0100 Subject: [PATCH 35/74] chore(deps): bump com.mebigfatguy.fb-contrib:fb-contrib from 7.6.15 to 7.7.0 (#7060) * chore(deps): bump com.mebigfatguy.fb-contrib:fb-contrib Bumps [com.mebigfatguy.fb-contrib:fb-contrib](https://github.com/mebigfatguy/fb-contrib) from 7.6.15 to 7.7.0. - [Commits](https://github.com/mebigfatguy/fb-contrib/commits/v7.7.0) --- updated-dependencies: - dependency-name: com.mebigfatguy.fb-contrib:fb-contrib dependency-version: 7.7.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * fix: suppress new warnings --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: vil02 <65706193+vil02@users.noreply.github.com> --- pom.xml | 2 +- spotbugs-exclude.xml | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7e936967208b..e99c8762ea3d 100644 --- a/pom.xml +++ b/pom.xml @@ -127,7 +127,7 @@ com.mebigfatguy.fb-contrib fb-contrib - 7.6.15 + 7.7.0 com.h3xstream.findsecbugs diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml index d2e094556d61..3e2f1ff84ca8 100644 --- a/spotbugs-exclude.xml +++ b/spotbugs-exclude.xml @@ -201,6 +201,12 @@ + + + + + + From b709941eb688f5c5d4e442eb9ab64568c234814f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 22:30:27 +0100 Subject: [PATCH 36/74] chore(deps): bump com.puppycrawl.tools:checkstyle from 12.1.1 to 12.1.2 (#7063) Bumps [com.puppycrawl.tools:checkstyle](https://github.com/checkstyle/checkstyle) from 12.1.1 to 12.1.2. - [Release notes](https://github.com/checkstyle/checkstyle/releases) - [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-12.1.1...checkstyle-12.1.2) --- updated-dependencies: - dependency-name: com.puppycrawl.tools:checkstyle dependency-version: 12.1.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e99c8762ea3d..6126bbe4d6c5 100644 --- a/pom.xml +++ b/pom.xml @@ -112,7 +112,7 @@ com.puppycrawl.tools checkstyle - 12.1.1 + 12.1.2 From a008cc2b0889ed51bf47e673e5f056e97f64cae1 Mon Sep 17 00:00:00 2001 From: Deniz Altunkapan Date: Wed, 12 Nov 2025 14:22:21 +0100 Subject: [PATCH 37/74] Update DIRECTORY.md (#6809) Co-authored-by: DenizAltunkapan --- DIRECTORY.md | 57 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index eca2453fad0f..f15d65c18c3f 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -13,6 +13,7 @@ - 📄 [AllPathsFromSourceToTarget](src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java) - 📄 [ArrayCombination](src/main/java/com/thealgorithms/backtracking/ArrayCombination.java) - 📄 [Combination](src/main/java/com/thealgorithms/backtracking/Combination.java) + - 📄 [CombinationSum](src/main/java/com/thealgorithms/backtracking/CombinationSum.java) - 📄 [CrosswordSolver](src/main/java/com/thealgorithms/backtracking/CrosswordSolver.java) - 📄 [FloodFill](src/main/java/com/thealgorithms/backtracking/FloodFill.java) - 📄 [KnightsTour](src/main/java/com/thealgorithms/backtracking/KnightsTour.java) @@ -28,6 +29,7 @@ - 📁 **bitmanipulation** - 📄 [BcdConversion](src/main/java/com/thealgorithms/bitmanipulation/BcdConversion.java) - 📄 [BinaryPalindromeCheck](src/main/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheck.java) + - 📄 [BitRotate](src/main/java/com/thealgorithms/bitmanipulation/BitRotate.java) - 📄 [BitSwap](src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java) - 📄 [BitwiseGCD](src/main/java/com/thealgorithms/bitmanipulation/BitwiseGCD.java) - 📄 [BooleanAlgebraGates](src/main/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGates.java) @@ -93,6 +95,12 @@ - 📄 [LFSR](src/main/java/com/thealgorithms/ciphers/a5/LFSR.java) - 📄 [Utils](src/main/java/com/thealgorithms/ciphers/a5/Utils.java) - 📁 **compression** + - 📄 [ArithmeticCoding](src/main/java/com/thealgorithms/compression/ArithmeticCoding.java) + - 📄 [BurrowsWheelerTransform](src/main/java/com/thealgorithms/compression/BurrowsWheelerTransform.java) + - 📄 [LZ77](src/main/java/com/thealgorithms/compression/LZ77.java) + - 📄 [LZ78](src/main/java/com/thealgorithms/compression/LZ78.java) + - 📄 [LZW](src/main/java/com/thealgorithms/compression/LZW.java) + - 📄 [MoveToFront](src/main/java/com/thealgorithms/compression/MoveToFront.java) - 📄 [RunLengthEncoding](src/main/java/com/thealgorithms/compression/RunLengthEncoding.java) - 📄 [ShannonFano](src/main/java/com/thealgorithms/compression/ShannonFano.java) - 📁 **conversions** @@ -173,7 +181,6 @@ - 📄 [FordFulkerson](src/main/java/com/thealgorithms/datastructures/graphs/FordFulkerson.java) - 📄 [Graphs](src/main/java/com/thealgorithms/datastructures/graphs/Graphs.java) - 📄 [HamiltonianCycle](src/main/java/com/thealgorithms/datastructures/graphs/HamiltonianCycle.java) - - 📄 [HierholzerAlgorithm](src/main/java/com/thealgorithms/graph/HierholzerAlgorithm.java) - 📄 [JohnsonsAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithm.java) - 📄 [KahnsAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/KahnsAlgorithm.java) - 📄 [Kosaraju](src/main/java/com/thealgorithms/datastructures/graphs/Kosaraju.java) @@ -358,8 +365,10 @@ - 📄 [WildcardMatching](src/main/java/com/thealgorithms/dynamicprogramming/WildcardMatching.java) - 📄 [WineProblem](src/main/java/com/thealgorithms/dynamicprogramming/WineProblem.java) - 📁 **geometry** + - 📄 [BentleyOttmann](src/main/java/com/thealgorithms/geometry/BentleyOttmann.java) - 📄 [BresenhamLine](src/main/java/com/thealgorithms/geometry/BresenhamLine.java) - 📄 [ConvexHull](src/main/java/com/thealgorithms/geometry/ConvexHull.java) + - 📄 [DDALine](src/main/java/com/thealgorithms/geometry/DDALine.java) - 📄 [GrahamScan](src/main/java/com/thealgorithms/geometry/GrahamScan.java) - 📄 [Haversine](src/main/java/com/thealgorithms/geometry/Haversine.java) - 📄 [MidpointCircle](src/main/java/com/thealgorithms/geometry/MidpointCircle.java) @@ -372,10 +381,13 @@ - 📄 [Dinic](src/main/java/com/thealgorithms/graph/Dinic.java) - 📄 [Edmonds](src/main/java/com/thealgorithms/graph/Edmonds.java) - 📄 [EdmondsKarp](src/main/java/com/thealgorithms/graph/EdmondsKarp.java) + - 📄 [HierholzerAlgorithm](src/main/java/com/thealgorithms/graph/HierholzerAlgorithm.java) + - 📄 [HierholzerEulerianPath](src/main/java/com/thealgorithms/graph/HierholzerEulerianPath.java) - 📄 [HopcroftKarp](src/main/java/com/thealgorithms/graph/HopcroftKarp.java) - 📄 [HungarianAlgorithm](src/main/java/com/thealgorithms/graph/HungarianAlgorithm.java) - 📄 [PredecessorConstrainedDfs](src/main/java/com/thealgorithms/graph/PredecessorConstrainedDfs.java) - 📄 [PushRelabel](src/main/java/com/thealgorithms/graph/PushRelabel.java) + - 📄 [StoerWagner](src/main/java/com/thealgorithms/graph/StoerWagner.java) - 📄 [StronglyConnectedComponentOptimized](src/main/java/com/thealgorithms/graph/StronglyConnectedComponentOptimized.java) - 📄 [TravelingSalesman](src/main/java/com/thealgorithms/graph/TravelingSalesman.java) - 📄 [YensKShortestPaths](src/main/java/com/thealgorithms/graph/YensKShortestPaths.java) @@ -420,6 +432,7 @@ - 📄 [BinomialCoefficient](src/main/java/com/thealgorithms/maths/BinomialCoefficient.java) - 📄 [CatalanNumbers](src/main/java/com/thealgorithms/maths/CatalanNumbers.java) - 📄 [Ceil](src/main/java/com/thealgorithms/maths/Ceil.java) + - 📄 [ChebyshevIteration](src/main/java/com/thealgorithms/maths/ChebyshevIteration.java) - 📄 [ChineseRemainderTheorem](src/main/java/com/thealgorithms/maths/ChineseRemainderTheorem.java) - 📄 [CircularConvolutionFFT](src/main/java/com/thealgorithms/maths/CircularConvolutionFFT.java) - 📄 [CollatzConjecture](src/main/java/com/thealgorithms/maths/CollatzConjecture.java) @@ -478,6 +491,7 @@ - 📄 [Median](src/main/java/com/thealgorithms/maths/Median.java) - 📄 [MinValue](src/main/java/com/thealgorithms/maths/MinValue.java) - 📄 [Mode](src/main/java/com/thealgorithms/maths/Mode.java) + - 📄 [Neville](src/main/java/com/thealgorithms/maths/Neville.java) - 📄 [NonRepeatingElement](src/main/java/com/thealgorithms/maths/NonRepeatingElement.java) - 📄 [NthUglyNumber](src/main/java/com/thealgorithms/maths/NthUglyNumber.java) - 📄 [NumberOfDigits](src/main/java/com/thealgorithms/maths/NumberOfDigits.java) @@ -531,6 +545,7 @@ - 📄 [ZellersCongruence](src/main/java/com/thealgorithms/maths/ZellersCongruence.java) - 📁 **matrix** - 📄 [InverseOfMatrix](src/main/java/com/thealgorithms/matrix/InverseOfMatrix.java) + - 📄 [LUDecomposition](src/main/java/com/thealgorithms/matrix/LUDecomposition.java) - 📄 [MatrixMultiplication](src/main/java/com/thealgorithms/matrix/MatrixMultiplication.java) - 📄 [MatrixRank](src/main/java/com/thealgorithms/matrix/MatrixRank.java) - 📄 [MatrixTranspose](src/main/java/com/thealgorithms/matrix/MatrixTranspose.java) @@ -591,7 +606,6 @@ - 📄 [PageRank](src/main/java/com/thealgorithms/others/PageRank.java) - 📄 [PasswordGen](src/main/java/com/thealgorithms/others/PasswordGen.java) - 📄 [PerlinNoise](src/main/java/com/thealgorithms/others/PerlinNoise.java) - - 📄 [PrintAMatrixInSpiralOrder](src/main/java/com/thealgorithms/others/PrintAMatrixInSpiralOrder.java) - 📄 [QueueUsingTwoStacks](src/main/java/com/thealgorithms/others/QueueUsingTwoStacks.java) - 📄 [SkylineProblem](src/main/java/com/thealgorithms/others/SkylineProblem.java) - 📄 [TwoPointers](src/main/java/com/thealgorithms/others/TwoPointers.java) @@ -599,7 +613,14 @@ - 📁 **cn** - 📄 [HammingDistance](src/main/java/com/thealgorithms/others/cn/HammingDistance.java) - 📁 **physics** + - 📄 [CoulombsLaw](src/main/java/com/thealgorithms/physics/CoulombsLaw.java) + - 📄 [DampedOscillator](src/main/java/com/thealgorithms/physics/DampedOscillator.java) + - 📄 [ElasticCollision2D](src/main/java/com/thealgorithms/physics/ElasticCollision2D.java) + - 📄 [Gravitation](src/main/java/com/thealgorithms/physics/Gravitation.java) - 📄 [GroundToGroundProjectileMotion](src/main/java/com/thealgorithms/physics/GroundToGroundProjectileMotion.java) + - 📄 [Kinematics](src/main/java/com/thealgorithms/physics/Kinematics.java) + - 📄 [ProjectileMotion](src/main/java/com/thealgorithms/physics/ProjectileMotion.java) + - 📄 [SimplePendulumRK4](src/main/java/com/thealgorithms/physics/SimplePendulumRK4.java) - 📁 **puzzlesandgames** - 📄 [Sudoku](src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java) - 📄 [TowerOfHanoi](src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java) @@ -649,7 +670,7 @@ - 📄 [BoyerMoore](src/main/java/com/thealgorithms/searches/BoyerMoore.java) - 📄 [BreadthFirstSearch](src/main/java/com/thealgorithms/searches/BreadthFirstSearch.java) - 📄 [DepthFirstSearch](src/main/java/com/thealgorithms/searches/DepthFirstSearch.java) - - 📄 [ExponentalSearch](src/main/java/com/thealgorithms/searches/ExponentalSearch.java) + - 📄 [ExponentialSearch](src/main/java/com/thealgorithms/searches/ExponentialSearch.java) - 📄 [FibonacciSearch](src/main/java/com/thealgorithms/searches/FibonacciSearch.java) - 📄 [HowManyTimesRotated](src/main/java/com/thealgorithms/searches/HowManyTimesRotated.java) - 📄 [InterpolationSearch](src/main/java/com/thealgorithms/searches/InterpolationSearch.java) @@ -758,6 +779,7 @@ - 📄 [SortStack](src/main/java/com/thealgorithms/stacks/SortStack.java) - 📄 [StackPostfixNotation](src/main/java/com/thealgorithms/stacks/StackPostfixNotation.java) - 📄 [StackUsingTwoQueues](src/main/java/com/thealgorithms/stacks/StackUsingTwoQueues.java) + - 📄 [TrappingRainwater](src/main/java/com/thealgorithms/stacks/TrappingRainwater.java) - 📁 **strings** - 📄 [AhoCorasick](src/main/java/com/thealgorithms/strings/AhoCorasick.java) - 📄 [Alphabetical](src/main/java/com/thealgorithms/strings/Alphabetical.java) @@ -808,6 +830,7 @@ - 📁 **backtracking** - 📄 [AllPathsFromSourceToTargetTest](src/test/java/com/thealgorithms/backtracking/AllPathsFromSourceToTargetTest.java) - 📄 [ArrayCombinationTest](src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java) + - 📄 [CombinationSumTest](src/test/java/com/thealgorithms/backtracking/CombinationSumTest.java) - 📄 [CombinationTest](src/test/java/com/thealgorithms/backtracking/CombinationTest.java) - 📄 [CrosswordSolverTest](src/test/java/com/thealgorithms/backtracking/CrosswordSolverTest.java) - 📄 [FloodFillTest](src/test/java/com/thealgorithms/backtracking/FloodFillTest.java) @@ -824,6 +847,7 @@ - 📁 **bitmanipulation** - 📄 [BcdConversionTest](src/test/java/com/thealgorithms/bitmanipulation/BcdConversionTest.java) - 📄 [BinaryPalindromeCheckTest](src/test/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheckTest.java) + - 📄 [BitRotateTest](src/test/java/com/thealgorithms/bitmanipulation/BitRotateTest.java) - 📄 [BitSwapTest](src/test/java/com/thealgorithms/bitmanipulation/BitSwapTest.java) - 📄 [BitwiseGCDTest](src/test/java/com/thealgorithms/bitmanipulation/BitwiseGCDTest.java) - 📄 [BooleanAlgebraGatesTest](src/test/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGatesTest.java) @@ -884,6 +908,12 @@ - 📄 [A5KeyStreamGeneratorTest](src/test/java/com/thealgorithms/ciphers/a5/A5KeyStreamGeneratorTest.java) - 📄 [LFSRTest](src/test/java/com/thealgorithms/ciphers/a5/LFSRTest.java) - 📁 **compression** + - 📄 [ArithmeticCodingTest](src/test/java/com/thealgorithms/compression/ArithmeticCodingTest.java) + - 📄 [BurrowsWheelerTransformTest](src/test/java/com/thealgorithms/compression/BurrowsWheelerTransformTest.java) + - 📄 [LZ77Test](src/test/java/com/thealgorithms/compression/LZ77Test.java) + - 📄 [LZ78Test](src/test/java/com/thealgorithms/compression/LZ78Test.java) + - 📄 [LZWTest](src/test/java/com/thealgorithms/compression/LZWTest.java) + - 📄 [MoveToFrontTest](src/test/java/com/thealgorithms/compression/MoveToFrontTest.java) - 📄 [RunLengthEncodingTest](src/test/java/com/thealgorithms/compression/RunLengthEncodingTest.java) - 📄 [ShannonFanoTest](src/test/java/com/thealgorithms/compression/ShannonFanoTest.java) - 📁 **conversions** @@ -1114,8 +1144,10 @@ - 📄 [WildcardMatchingTest](src/test/java/com/thealgorithms/dynamicprogramming/WildcardMatchingTest.java) - 📄 [WineProblemTest](src/test/java/com/thealgorithms/dynamicprogramming/WineProblemTest.java) - 📁 **geometry** + - 📄 [BentleyOttmannTest](src/test/java/com/thealgorithms/geometry/BentleyOttmannTest.java) - 📄 [BresenhamLineTest](src/test/java/com/thealgorithms/geometry/BresenhamLineTest.java) - 📄 [ConvexHullTest](src/test/java/com/thealgorithms/geometry/ConvexHullTest.java) + - 📄 [DDALineTest](src/test/java/com/thealgorithms/geometry/DDALineTest.java) - 📄 [GrahamScanTest](src/test/java/com/thealgorithms/geometry/GrahamScanTest.java) - 📄 [HaversineTest](src/test/java/com/thealgorithms/geometry/HaversineTest.java) - 📄 [MidpointCircleTest](src/test/java/com/thealgorithms/geometry/MidpointCircleTest.java) @@ -1128,9 +1160,13 @@ - 📄 [DinicTest](src/test/java/com/thealgorithms/graph/DinicTest.java) - 📄 [EdmondsKarpTest](src/test/java/com/thealgorithms/graph/EdmondsKarpTest.java) - 📄 [EdmondsTest](src/test/java/com/thealgorithms/graph/EdmondsTest.java) + - 📄 [HierholzerAlgorithmTest](src/test/java/com/thealgorithms/graph/HierholzerAlgorithmTest.java) + - 📄 [HierholzerEulerianPathTest](src/test/java/com/thealgorithms/graph/HierholzerEulerianPathTest.java) - 📄 [HopcroftKarpTest](src/test/java/com/thealgorithms/graph/HopcroftKarpTest.java) + - 📄 [HungarianAlgorithmTest](src/test/java/com/thealgorithms/graph/HungarianAlgorithmTest.java) - 📄 [PredecessorConstrainedDfsTest](src/test/java/com/thealgorithms/graph/PredecessorConstrainedDfsTest.java) - 📄 [PushRelabelTest](src/test/java/com/thealgorithms/graph/PushRelabelTest.java) + - 📄 [StoerWagnerTest](src/test/java/com/thealgorithms/graph/StoerWagnerTest.java) - 📄 [StronglyConnectedComponentOptimizedTest](src/test/java/com/thealgorithms/graph/StronglyConnectedComponentOptimizedTest.java) - 📄 [TravelingSalesmanTest](src/test/java/com/thealgorithms/graph/TravelingSalesmanTest.java) - 📄 [YensKShortestPathsTest](src/test/java/com/thealgorithms/graph/YensKShortestPathsTest.java) @@ -1172,6 +1208,7 @@ - 📄 [BinomialCoefficientTest](src/test/java/com/thealgorithms/maths/BinomialCoefficientTest.java) - 📄 [CatalanNumbersTest](src/test/java/com/thealgorithms/maths/CatalanNumbersTest.java) - 📄 [CeilTest](src/test/java/com/thealgorithms/maths/CeilTest.java) + - 📄 [ChebyshevIterationTest](src/test/java/com/thealgorithms/maths/ChebyshevIterationTest.java) - 📄 [ChineseRemainderTheoremTest](src/test/java/com/thealgorithms/maths/ChineseRemainderTheoremTest.java) - 📄 [CollatzConjectureTest](src/test/java/com/thealgorithms/maths/CollatzConjectureTest.java) - 📄 [CombinationsTest](src/test/java/com/thealgorithms/maths/CombinationsTest.java) @@ -1211,6 +1248,7 @@ - 📄 [HarshadNumberTest](src/test/java/com/thealgorithms/maths/HarshadNumberTest.java) - 📄 [HeronsFormulaTest](src/test/java/com/thealgorithms/maths/HeronsFormulaTest.java) - 📄 [JosephusProblemTest](src/test/java/com/thealgorithms/maths/JosephusProblemTest.java) + - 📄 [JugglerSequenceTest](src/test/java/com/thealgorithms/maths/JugglerSequenceTest.java) - 📄 [KaprekarNumbersTest](src/test/java/com/thealgorithms/maths/KaprekarNumbersTest.java) - 📄 [KaratsubaMultiplicationTest](src/test/java/com/thealgorithms/maths/KaratsubaMultiplicationTest.java) - 📄 [KeithNumberTest](src/test/java/com/thealgorithms/maths/KeithNumberTest.java) @@ -1226,6 +1264,7 @@ - 📄 [MedianTest](src/test/java/com/thealgorithms/maths/MedianTest.java) - 📄 [MinValueTest](src/test/java/com/thealgorithms/maths/MinValueTest.java) - 📄 [ModeTest](src/test/java/com/thealgorithms/maths/ModeTest.java) + - 📄 [NevilleTest](src/test/java/com/thealgorithms/maths/NevilleTest.java) - 📄 [NonRepeatingElementTest](src/test/java/com/thealgorithms/maths/NonRepeatingElementTest.java) - 📄 [NthUglyNumberTest](src/test/java/com/thealgorithms/maths/NthUglyNumberTest.java) - 📄 [NumberOfDigitsTest](src/test/java/com/thealgorithms/maths/NumberOfDigitsTest.java) @@ -1275,14 +1314,15 @@ - 📄 [PrimeFactorizationTest](src/test/java/com/thealgorithms/maths/prime/PrimeFactorizationTest.java) - 📁 **matrix** - 📄 [InverseOfMatrixTest](src/test/java/com/thealgorithms/matrix/InverseOfMatrixTest.java) + - 📄 [LUDecompositionTest](src/test/java/com/thealgorithms/matrix/LUDecompositionTest.java) - 📄 [MatrixMultiplicationTest](src/test/java/com/thealgorithms/matrix/MatrixMultiplicationTest.java) - 📄 [MatrixRankTest](src/test/java/com/thealgorithms/matrix/MatrixRankTest.java) - 📄 [MatrixTransposeTest](src/test/java/com/thealgorithms/matrix/MatrixTransposeTest.java) - 📄 [MatrixUtilTest](src/test/java/com/thealgorithms/matrix/MatrixUtilTest.java) - 📄 [MedianOfMatrixTest](src/test/java/com/thealgorithms/matrix/MedianOfMatrixTest.java) - 📄 [MirrorOfMatrixTest](src/test/java/com/thealgorithms/matrix/MirrorOfMatrixTest.java) + - 📄 [PrintAMatrixInSpiralOrderTest](src/test/java/com/thealgorithms/matrix/PrintAMatrixInSpiralOrderTest.java) - 📄 [SolveSystemTest](src/test/java/com/thealgorithms/matrix/SolveSystemTest.java) - - 📄 [TestPrintMatrixInSpiralOrder](src/test/java/com/thealgorithms/matrix/TestPrintMatrixInSpiralOrder.java) - 📁 **misc** - 📄 [ColorContrastRatioTest](src/test/java/com/thealgorithms/misc/ColorContrastRatioTest.java) - 📄 [MapReduceTest](src/test/java/com/thealgorithms/misc/MapReduceTest.java) @@ -1323,13 +1363,19 @@ - 📄 [PerlinNoiseTest](src/test/java/com/thealgorithms/others/PerlinNoiseTest.java) - 📄 [QueueUsingTwoStacksTest](src/test/java/com/thealgorithms/others/QueueUsingTwoStacksTest.java) - 📄 [SkylineProblemTest](src/test/java/com/thealgorithms/others/SkylineProblemTest.java) - - 📄 [TestPrintMatrixInSpiralOrder](src/test/java/com/thealgorithms/others/TestPrintMatrixInSpiralOrder.java) - 📄 [TwoPointersTest](src/test/java/com/thealgorithms/others/TwoPointersTest.java) - 📄 [WorstFitCPUTest](src/test/java/com/thealgorithms/others/WorstFitCPUTest.java) - 📁 **cn** - 📄 [HammingDistanceTest](src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java) - 📁 **physics** + - 📄 [CoulombsLawTest](src/test/java/com/thealgorithms/physics/CoulombsLawTest.java) + - 📄 [DampedOscillatorTest](src/test/java/com/thealgorithms/physics/DampedOscillatorTest.java) + - 📄 [ElasticCollision2DTest](src/test/java/com/thealgorithms/physics/ElasticCollision2DTest.java) + - 📄 [GravitationTest](src/test/java/com/thealgorithms/physics/GravitationTest.java) - 📄 [GroundToGroundProjectileMotionTest](src/test/java/com/thealgorithms/physics/GroundToGroundProjectileMotionTest.java) + - 📄 [KinematicsTest](src/test/java/com/thealgorithms/physics/KinematicsTest.java) + - 📄 [ProjectileMotionTest](src/test/java/com/thealgorithms/physics/ProjectileMotionTest.java) + - 📄 [SimplePendulumRK4Test](src/test/java/com/thealgorithms/physics/SimplePendulumRK4Test.java) - 📁 **puzzlesandgames** - 📄 [SudokuTest](src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java) - 📄 [TowerOfHanoiTest](src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java) @@ -1487,6 +1533,7 @@ - 📄 [SortStackTest](src/test/java/com/thealgorithms/stacks/SortStackTest.java) - 📄 [StackPostfixNotationTest](src/test/java/com/thealgorithms/stacks/StackPostfixNotationTest.java) - 📄 [StackUsingTwoQueuesTest](src/test/java/com/thealgorithms/stacks/StackUsingTwoQueuesTest.java) + - 📄 [TrappingRainwaterTest](src/test/java/com/thealgorithms/stacks/TrappingRainwaterTest.java) - 📁 **strings** - 📄 [AhoCorasickTest](src/test/java/com/thealgorithms/strings/AhoCorasickTest.java) - 📄 [AlphabeticalTest](src/test/java/com/thealgorithms/strings/AlphabeticalTest.java) From 8a339ef2e2ad0ec7bc3fb9ce8076fc33a61d548e Mon Sep 17 00:00:00 2001 From: Krishna Date: Sat, 15 Nov 2025 14:52:36 +0530 Subject: [PATCH 38/74] Add Temperature Conversion Utility (#7066) - Implements conversions between Celsius, Fahrenheit, and Kelvin - Includes all 6 conversion methods - Adds comprehensive unit tests with edge cases - Fixes #6936 --- .../conversions/TemperatureConverter.java | 46 ++++++++++++++++ .../conversions/TemperatureConverterTest.java | 54 +++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 src/main/java/com/thealgorithms/conversions/TemperatureConverter.java create mode 100644 src/test/java/com/thealgorithms/conversions/TemperatureConverterTest.java diff --git a/src/main/java/com/thealgorithms/conversions/TemperatureConverter.java b/src/main/java/com/thealgorithms/conversions/TemperatureConverter.java new file mode 100644 index 000000000000..901db17c665d --- /dev/null +++ b/src/main/java/com/thealgorithms/conversions/TemperatureConverter.java @@ -0,0 +1,46 @@ +package com.thealgorithms.conversions; + +/** + * A utility class to convert between different temperature units. + * + *

This class supports conversions between the following units: + *

    + *
  • Celsius
  • + *
  • Fahrenheit
  • + *
  • Kelvin
  • + *
+ * + *

This class is final and cannot be instantiated. + * + * @author krishna-medapati (https://github.com/krishna-medapati) + * @see Wikipedia: Temperature Conversion + */ +public final class TemperatureConverter { + + private TemperatureConverter() { + } + + public static double celsiusToFahrenheit(double celsius) { + return celsius * 9.0 / 5.0 + 32.0; + } + + public static double celsiusToKelvin(double celsius) { + return celsius + 273.15; + } + + public static double fahrenheitToCelsius(double fahrenheit) { + return (fahrenheit - 32.0) * 5.0 / 9.0; + } + + public static double fahrenheitToKelvin(double fahrenheit) { + return (fahrenheit - 32.0) * 5.0 / 9.0 + 273.15; + } + + public static double kelvinToCelsius(double kelvin) { + return kelvin - 273.15; + } + + public static double kelvinToFahrenheit(double kelvin) { + return (kelvin - 273.15) * 9.0 / 5.0 + 32.0; + } +} diff --git a/src/test/java/com/thealgorithms/conversions/TemperatureConverterTest.java b/src/test/java/com/thealgorithms/conversions/TemperatureConverterTest.java new file mode 100644 index 000000000000..24d55b706f36 --- /dev/null +++ b/src/test/java/com/thealgorithms/conversions/TemperatureConverterTest.java @@ -0,0 +1,54 @@ +package com.thealgorithms.conversions; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class TemperatureConverterTest { + + private static final double DELTA = 0.01; + + @Test + void testCelsiusToFahrenheit() { + assertEquals(32.0, TemperatureConverter.celsiusToFahrenheit(0.0), DELTA); + assertEquals(212.0, TemperatureConverter.celsiusToFahrenheit(100.0), DELTA); + assertEquals(-40.0, TemperatureConverter.celsiusToFahrenheit(-40.0), DELTA); + assertEquals(98.6, TemperatureConverter.celsiusToFahrenheit(37.0), DELTA); + } + + @Test + void testCelsiusToKelvin() { + assertEquals(273.15, TemperatureConverter.celsiusToKelvin(0.0), DELTA); + assertEquals(373.15, TemperatureConverter.celsiusToKelvin(100.0), DELTA); + assertEquals(233.15, TemperatureConverter.celsiusToKelvin(-40.0), DELTA); + } + + @Test + void testFahrenheitToCelsius() { + assertEquals(0.0, TemperatureConverter.fahrenheitToCelsius(32.0), DELTA); + assertEquals(100.0, TemperatureConverter.fahrenheitToCelsius(212.0), DELTA); + assertEquals(-40.0, TemperatureConverter.fahrenheitToCelsius(-40.0), DELTA); + assertEquals(37.0, TemperatureConverter.fahrenheitToCelsius(98.6), DELTA); + } + + @Test + void testFahrenheitToKelvin() { + assertEquals(273.15, TemperatureConverter.fahrenheitToKelvin(32.0), DELTA); + assertEquals(373.15, TemperatureConverter.fahrenheitToKelvin(212.0), DELTA); + assertEquals(233.15, TemperatureConverter.fahrenheitToKelvin(-40.0), DELTA); + } + + @Test + void testKelvinToCelsius() { + assertEquals(0.0, TemperatureConverter.kelvinToCelsius(273.15), DELTA); + assertEquals(100.0, TemperatureConverter.kelvinToCelsius(373.15), DELTA); + assertEquals(-273.15, TemperatureConverter.kelvinToCelsius(0.0), DELTA); + } + + @Test + void testKelvinToFahrenheit() { + assertEquals(32.0, TemperatureConverter.kelvinToFahrenheit(273.15), DELTA); + assertEquals(212.0, TemperatureConverter.kelvinToFahrenheit(373.15), DELTA); + assertEquals(-40.0, TemperatureConverter.kelvinToFahrenheit(233.15), DELTA); + } +} From 98eecb9f16003e612ad8d84ed6f3c78ae10c7005 Mon Sep 17 00:00:00 2001 From: Taranjeet Singh Kalsi Date: Sat, 15 Nov 2025 15:02:06 +0530 Subject: [PATCH 39/74] Added program to check Smith number (#6955) added smith number program --- .../com/thealgorithms/maths/SmithNumber.java | 52 +++++++++++++++++++ .../thealgorithms/maths/SmithNumberTest.java | 22 ++++++++ 2 files changed, 74 insertions(+) create mode 100644 src/main/java/com/thealgorithms/maths/SmithNumber.java create mode 100644 src/test/java/com/thealgorithms/maths/SmithNumberTest.java diff --git a/src/main/java/com/thealgorithms/maths/SmithNumber.java b/src/main/java/com/thealgorithms/maths/SmithNumber.java new file mode 100644 index 000000000000..c06e0023d9bb --- /dev/null +++ b/src/main/java/com/thealgorithms/maths/SmithNumber.java @@ -0,0 +1,52 @@ +package com.thealgorithms.maths; + +import com.thealgorithms.maths.Prime.PrimeCheck; + +/** + * In number theory, a smith number is a composite number for which, in a given number base, + * the sum of its digits is equal to the sum of the digits in its prime factorization in the same base. + * + * For example, in base 10, 378 = 21 X 33 X 71 is a Smith number since 3 + 7 + 8 = 2 X 1 + 3 X 3 + 7 X 1, + * and 22 = 21 X 111 is a Smith number, because 2 + 2 = 2 X 1 + (1 + 1) X 1. + * + * Wiki: https://en.wikipedia.org/wiki/Smith_number + */ +public final class SmithNumber { + + private SmithNumber() { + } + + private static int primeFactorDigitSum(int n) { + int sum = 0; + int num = n; + + // Factorize the number using trial division + for (int i = 2; i * i <= num; i++) { + while (n % i == 0) { // while i divides n + sum += SumOfDigits.sumOfDigits(i); // add sum of digits of factor + n /= i; // divide n by the factor + } + } + + // If n is still > 1, it itself is a prime factor + if (n > 1) { + sum += SumOfDigits.sumOfDigits(n); + } + + return sum; + } + + /** + * Check if {@code number} is Smith number or not + * + * @param number the number + * @return {@code true} if {@code number} is a Smith number, otherwise false + */ + public static boolean isSmithNumber(int number) { + if (PrimeCheck.isPrime(number)) { + return false; // Smith numbers must be composite + } + + return SumOfDigits.sumOfDigits(number) == primeFactorDigitSum(number); + } +} diff --git a/src/test/java/com/thealgorithms/maths/SmithNumberTest.java b/src/test/java/com/thealgorithms/maths/SmithNumberTest.java new file mode 100644 index 000000000000..4e2ba0b88e33 --- /dev/null +++ b/src/test/java/com/thealgorithms/maths/SmithNumberTest.java @@ -0,0 +1,22 @@ +package com.thealgorithms.maths; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +class SmithNumberTest { + + @ParameterizedTest + @CsvSource({"4", "22", "121", "562", "985", "4937775"}) + void positiveSmithNumbersTest(int n) { + assertTrue(SmithNumber.isSmithNumber(n)); + } + + @ParameterizedTest + @CsvSource({"2", "11", "100", "550", "999", "1234557"}) + void negativeSmithNumbersTest(int n) { + assertFalse(SmithNumber.isSmithNumber(n)); + } +} From 3979e824b7683c5435df1b8d703433123da9a31c Mon Sep 17 00:00:00 2001 From: Krishna Date: Sat, 15 Nov 2025 23:06:01 +0530 Subject: [PATCH 40/74] Add Power of Four Check using bit manipulation (#7065) * Add Power of Four Check using bit manipulation - Implements isPowerOfFour method using bit manipulation - Checks if number is power of two and has bit at even position - Includes comprehensive unit tests - Fixes #6940 * Fix code formatting in PowerOfFourTest * Move PowerOfFour classes to maths package * Fix package declaration in PowerOfFourTest * Fix code formatting in PowerOfFourTest * Remove redundant import from PowerOfFourTest * Remove unrelated file --- .../com/thealgorithms/maths/PowerOfFour.java | 36 +++++++++++++++++++ .../thealgorithms/maths/PowerOfFourTest.java | 36 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 src/main/java/com/thealgorithms/maths/PowerOfFour.java create mode 100644 src/test/java/com/thealgorithms/maths/PowerOfFourTest.java diff --git a/src/main/java/com/thealgorithms/maths/PowerOfFour.java b/src/main/java/com/thealgorithms/maths/PowerOfFour.java new file mode 100644 index 000000000000..e5fe6255821b --- /dev/null +++ b/src/main/java/com/thealgorithms/maths/PowerOfFour.java @@ -0,0 +1,36 @@ +package com.thealgorithms.maths; + +/** + * Utility class for checking if a number is a power of four. + * A power of four is a number that can be expressed as 4^n where n is a non-negative integer. + * This class provides a method to determine if a given integer is a power of four using bit manipulation. + * + * @author krishna-medapati (https://github.com/krishna-medapati) + */ +public final class PowerOfFour { + private PowerOfFour() { + } + + /** + * Checks if the given integer is a power of four. + * + * A number is considered a power of four if: + * 1. It is greater than zero + * 2. It has exactly one '1' bit in its binary representation (power of two) + * 3. The '1' bit is at an even position (0, 2, 4, 6, ...) + * + * The method uses the mask 0x55555555 (binary: 01010101010101010101010101010101) + * to check if the set bit is at an even position. + * + * @param number the integer to check + * @return true if the number is a power of four, false otherwise + */ + public static boolean isPowerOfFour(int number) { + if (number <= 0) { + return false; + } + boolean isPowerOfTwo = (number & (number - 1)) == 0; + boolean hasEvenBitPosition = (number & 0x55555555) != 0; + return isPowerOfTwo && hasEvenBitPosition; + } +} diff --git a/src/test/java/com/thealgorithms/maths/PowerOfFourTest.java b/src/test/java/com/thealgorithms/maths/PowerOfFourTest.java new file mode 100644 index 000000000000..c91f8b3cf1b5 --- /dev/null +++ b/src/test/java/com/thealgorithms/maths/PowerOfFourTest.java @@ -0,0 +1,36 @@ +package com.thealgorithms.maths; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class PowerOfFourTest { + + @Test + void testPowersOfFour() { + assertTrue(PowerOfFour.isPowerOfFour(1)); + assertTrue(PowerOfFour.isPowerOfFour(4)); + assertTrue(PowerOfFour.isPowerOfFour(16)); + assertTrue(PowerOfFour.isPowerOfFour(64)); + assertTrue(PowerOfFour.isPowerOfFour(256)); + assertTrue(PowerOfFour.isPowerOfFour(1024)); + } + + @Test + void testNonPowersOfFour() { + assertFalse(PowerOfFour.isPowerOfFour(2)); + assertFalse(PowerOfFour.isPowerOfFour(3)); + assertFalse(PowerOfFour.isPowerOfFour(5)); + assertFalse(PowerOfFour.isPowerOfFour(8)); + assertFalse(PowerOfFour.isPowerOfFour(15)); + assertFalse(PowerOfFour.isPowerOfFour(32)); + } + + @Test + void testEdgeCases() { + assertFalse(PowerOfFour.isPowerOfFour(0)); + assertFalse(PowerOfFour.isPowerOfFour(-1)); + assertFalse(PowerOfFour.isPowerOfFour(-4)); + } +} From 93811614b868b2d8f4e1aaa3f4918982036684ff Mon Sep 17 00:00:00 2001 From: GOPISETTI NAVADEEP <2400030007@kluniversity.in> Date: Sun, 16 Nov 2025 17:24:43 +0530 Subject: [PATCH 41/74] feat: add Count Set Bits algorithm (#7072) * feat: add Count Set Bits algorithm (issue #6931) * fix: correct CountSetBits algorithm logic * style: apply clang-format to CountSetBits files * fix: correct test expectations for CountSetBits * fix: correct test expectations for CountSetBits --- .../bitmanipulation/CountSetBits.java | 114 +++++++++--------- .../bitmanipulation/CountSetBitsTest.java | 56 +++++++-- 2 files changed, 100 insertions(+), 70 deletions(-) diff --git a/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java b/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java index 242f35fc35f2..7df522ca8f69 100644 --- a/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java +++ b/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java @@ -1,79 +1,79 @@ package com.thealgorithms.bitmanipulation; -public class CountSetBits { +/** + * Utility class to count total set bits from 1 to N + * A set bit is a bit in binary representation that is 1 + * + * @author navadeep + */ +public final class CountSetBits { + + private CountSetBits() { + // Utility class, prevent instantiation + } /** - * The below algorithm is called as Brian Kernighan's algorithm - * We can use Brian Kernighan’s algorithm to improve the above naive algorithm’s performance. - The idea is to only consider the set bits of an integer by turning off its rightmost set bit - (after counting it), so the next iteration of the loop considers the next rightmost bit. - - The expression n & (n-1) can be used to turn off the rightmost set bit of a number n. This - works as the expression n-1 flips all the bits after the rightmost set bit of n, including the - rightmost set bit itself. Therefore, n & (n-1) results in the last bit flipped of n. - - For example, consider number 52, which is 00110100 in binary, and has a total 3 bits set. - - 1st iteration of the loop: n = 52 - - 00110100 & (n) - 00110011 (n-1) - ~~~~~~~~ - 00110000 + * Counts total number of set bits in all numbers from 1 to n + * Time Complexity: O(log n) + * + * @param n the upper limit (inclusive) + * @return total count of set bits from 1 to n + * @throws IllegalArgumentException if n is negative + */ + public static int countSetBits(int n) { + if (n < 0) { + throw new IllegalArgumentException("Input must be non-negative"); + } + if (n == 0) { + return 0; + } - 2nd iteration of the loop: n = 48 + // Find the largest power of 2 <= n + int x = largestPowerOf2InNumber(n); - 00110000 & (n) - 00101111 (n-1) - ~~~~~~~~ - 00100000 + // Total bits at position x: x * 2^(x-1) + int bitsAtPositionX = x * (1 << (x - 1)); + // Remaining numbers after 2^x + int remainingNumbers = n - (1 << x) + 1; - 3rd iteration of the loop: n = 32 + // Recursively count for the rest + int rest = countSetBits(n - (1 << x)); - 00100000 & (n) - 00011111 (n-1) - ~~~~~~~~ - 00000000 (n = 0) + return bitsAtPositionX + remainingNumbers + rest; + } - * @param num takes Long number whose number of set bit is to be found - * @return the count of set bits in the binary equivalent - */ - public long countSetBits(long num) { - long cnt = 0; - while (num > 0) { - cnt++; - num &= (num - 1); + /** + * Finds the position of the most significant bit in n + * + * @param n the number + * @return position of MSB (0-indexed from right) + */ + private static int largestPowerOf2InNumber(int n) { + int position = 0; + while ((1 << position) <= n) { + position++; } - return cnt; + return position - 1; } /** - * This approach takes O(1) running time to count the set bits, but requires a pre-processing. + * Alternative naive approach - counts set bits by iterating through all numbers + * Time Complexity: O(n log n) * - * So, we divide our 32-bit input into 8-bit chunks, with four chunks. We have 8 bits in each chunk. - * - * Then the range is from 0-255 (0 to 2^7). - * So, we may need to count set bits from 0 to 255 in individual chunks. - * - * @param num takes a long number - * @return the count of set bits in the binary equivalent + * @param n the upper limit (inclusive) + * @return total count of set bits from 1 to n */ - public int lookupApproach(int num) { - int[] table = new int[256]; - table[0] = 0; - - for (int i = 1; i < 256; i++) { - table[i] = (i & 1) + table[i >> 1]; // i >> 1 equals to i/2 + public static int countSetBitsNaive(int n) { + if (n < 0) { + throw new IllegalArgumentException("Input must be non-negative"); } - int res = 0; - for (int i = 0; i < 4; i++) { - res += table[num & 0xff]; - num >>= 8; + int count = 0; + for (int i = 1; i <= n; i++) { + count += Integer.bitCount(i); } - - return res; + return count; } } diff --git a/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java b/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java index 61e0757f9c12..757c6edc0151 100644 --- a/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java +++ b/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java @@ -1,26 +1,56 @@ package com.thealgorithms.bitmanipulation; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.Test; -public class CountSetBitsTest { +class CountSetBitsTest { @Test - void testSetBits() { - CountSetBits csb = new CountSetBits(); - assertEquals(1L, csb.countSetBits(16)); - assertEquals(4, csb.countSetBits(15)); - assertEquals(5, csb.countSetBits(10000)); - assertEquals(5, csb.countSetBits(31)); + void testCountSetBitsZero() { + assertEquals(0, CountSetBits.countSetBits(0)); } @Test - void testSetBitsLookupApproach() { - CountSetBits csb = new CountSetBits(); - assertEquals(1L, csb.lookupApproach(16)); - assertEquals(4, csb.lookupApproach(15)); - assertEquals(5, csb.lookupApproach(10000)); - assertEquals(5, csb.lookupApproach(31)); + void testCountSetBitsOne() { + assertEquals(1, CountSetBits.countSetBits(1)); + } + + @Test + void testCountSetBitsSmallNumber() { + assertEquals(4, CountSetBits.countSetBits(3)); // 1(1) + 10(1) + 11(2) = 4 + } + + @Test + void testCountSetBitsFive() { + assertEquals(7, CountSetBits.countSetBits(5)); // 1 + 1 + 2 + 1 + 2 = 7 + } + + @Test + void testCountSetBitsTen() { + assertEquals(17, CountSetBits.countSetBits(10)); + } + + @Test + void testCountSetBitsLargeNumber() { + assertEquals(42, CountSetBits.countSetBits(20)); // Changed from 93 to 42 + } + + @Test + void testCountSetBitsPowerOfTwo() { + assertEquals(13, CountSetBits.countSetBits(8)); // Changed from 9 to 13 + } + + @Test + void testCountSetBitsNegativeInput() { + assertThrows(IllegalArgumentException.class, () -> CountSetBits.countSetBits(-1)); + } + + @Test + void testNaiveApproachMatchesOptimized() { + for (int i = 0; i <= 100; i++) { + assertEquals(CountSetBits.countSetBitsNaive(i), CountSetBits.countSetBits(i), "Mismatch at n = " + i); + } } } From c6880c195d778b1d19fc13d4be1ae09dc355de2f Mon Sep 17 00:00:00 2001 From: GOPISETTI NAVADEEP <2400030007@kluniversity.in> Date: Sun, 16 Nov 2025 17:30:21 +0530 Subject: [PATCH 42/74] feat: add Sieve of Eratosthenes algorithm (#7071) * feat: add Sieve of Eratosthenes algorithm - Implement Sieve of Eratosthenes for finding prime numbers up to n - Add comprehensive unit tests with edge cases - Include JavaDoc documentation - Time complexity: O(n log log n) - Space complexity: O(n) Resolves #6939 * fix: remove trailing spaces * fix: apply clang-format --- .../maths/SieveOfEratosthenes.java | 98 +++++++++++-------- .../maths/SieveOfEratosthenesTest.java | 60 ++++++++---- 2 files changed, 96 insertions(+), 62 deletions(-) diff --git a/src/main/java/com/thealgorithms/maths/SieveOfEratosthenes.java b/src/main/java/com/thealgorithms/maths/SieveOfEratosthenes.java index f22d22e8c6af..5a15c4201a15 100644 --- a/src/main/java/com/thealgorithms/maths/SieveOfEratosthenes.java +++ b/src/main/java/com/thealgorithms/maths/SieveOfEratosthenes.java @@ -1,66 +1,82 @@ package com.thealgorithms.maths; -import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; /** - * @brief utility class implementing Sieve of Eratosthenes + * Sieve of Eratosthenes Algorithm + * An efficient algorithm to find all prime numbers up to a given limit. + * + * Algorithm: + * 1. Create a boolean array of size n+1, initially all true + * 2. Mark 0 and 1 as not prime + * 3. For each number i from 2 to sqrt(n): + * - If i is still marked as prime + * - Mark all multiples of i (starting from i²) as not prime + * 4. Collect all numbers still marked as prime + * + * Time Complexity: O(n log log n) + * Space Complexity: O(n) + * + * @author Navadeep0007 + * @see Sieve of Eratosthenes */ public final class SieveOfEratosthenes { + private SieveOfEratosthenes() { + // Utility class, prevent instantiation } - private static void checkInput(int n) { - if (n <= 0) { - throw new IllegalArgumentException("n must be positive."); + /** + * Finds all prime numbers up to n using the Sieve of Eratosthenes algorithm + * + * @param n the upper limit (inclusive) + * @return a list of all prime numbers from 2 to n + * @throws IllegalArgumentException if n is negative + */ + public static List findPrimes(int n) { + if (n < 0) { + throw new IllegalArgumentException("Input must be non-negative"); } - } - private static Type[] sievePrimesTill(int n) { - checkInput(n); - Type[] isPrimeArray = new Type[n + 1]; - Arrays.fill(isPrimeArray, Type.PRIME); - isPrimeArray[0] = Type.NOT_PRIME; - isPrimeArray[1] = Type.NOT_PRIME; + if (n < 2) { + return new ArrayList<>(); + } + + // Create boolean array, initially all true + boolean[] isPrime = new boolean[n + 1]; + for (int i = 2; i <= n; i++) { + isPrime[i] = true; + } - double cap = Math.sqrt(n); - for (int i = 2; i <= cap; i++) { - if (isPrimeArray[i] == Type.PRIME) { - for (int j = 2; i * j <= n; j++) { - isPrimeArray[i * j] = Type.NOT_PRIME; + // Sieve process + for (int i = 2; i * i <= n; i++) { + if (isPrime[i]) { + // Mark all multiples of i as not prime + for (int j = i * i; j <= n; j += i) { + isPrime[j] = false; } } } - return isPrimeArray; - } - - private static int countPrimes(Type[] isPrimeArray) { - return (int) Arrays.stream(isPrimeArray).filter(element -> element == Type.PRIME).count(); - } - private static int[] extractPrimes(Type[] isPrimeArray) { - int numberOfPrimes = countPrimes(isPrimeArray); - int[] primes = new int[numberOfPrimes]; - int primeIndex = 0; - for (int curNumber = 0; curNumber < isPrimeArray.length; ++curNumber) { - if (isPrimeArray[curNumber] == Type.PRIME) { - primes[primeIndex++] = curNumber; + // Collect all prime numbers + List primes = new ArrayList<>(); + for (int i = 2; i <= n; i++) { + if (isPrime[i]) { + primes.add(i); } } + return primes; } /** - * @brief finds all of the prime numbers up to the given upper (inclusive) limit - * @param n upper (inclusive) limit - * @exception IllegalArgumentException n is non-positive - * @return the array of all primes up to the given number (inclusive) + * Counts the number of prime numbers up to n + * + * @param n the upper limit (inclusive) + * @return count of prime numbers from 2 to n */ - public static int[] findPrimesTill(int n) { - return extractPrimes(sievePrimesTill(n)); - } - - private enum Type { - PRIME, - NOT_PRIME, + public static int countPrimes(int n) { + return findPrimes(n).size(); } } diff --git a/src/test/java/com/thealgorithms/maths/SieveOfEratosthenesTest.java b/src/test/java/com/thealgorithms/maths/SieveOfEratosthenesTest.java index ebbd5df712fc..5d491a493ee7 100644 --- a/src/test/java/com/thealgorithms/maths/SieveOfEratosthenesTest.java +++ b/src/test/java/com/thealgorithms/maths/SieveOfEratosthenesTest.java @@ -1,46 +1,64 @@ package com.thealgorithms.maths; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.Arrays; +import java.util.List; import org.junit.jupiter.api.Test; +/** + * Test cases for Sieve of Eratosthenes algorithm + * + * @author Navadeep0007 + */ class SieveOfEratosthenesTest { + + @Test + void testPrimesUpTo10() { + List expected = Arrays.asList(2, 3, 5, 7); + assertEquals(expected, SieveOfEratosthenes.findPrimes(10)); + } + + @Test + void testPrimesUpTo30() { + List expected = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29); + assertEquals(expected, SieveOfEratosthenes.findPrimes(30)); + } + @Test - public void testfFindPrimesTill1() { - assertArrayEquals(new int[] {}, SieveOfEratosthenes.findPrimesTill(1)); + void testPrimesUpTo2() { + List expected = Arrays.asList(2); + assertEquals(expected, SieveOfEratosthenes.findPrimes(2)); } @Test - public void testfFindPrimesTill2() { - assertArrayEquals(new int[] {2}, SieveOfEratosthenes.findPrimesTill(2)); + void testPrimesUpTo1() { + assertTrue(SieveOfEratosthenes.findPrimes(1).isEmpty()); } @Test - public void testfFindPrimesTill4() { - var primesTill4 = new int[] {2, 3}; - assertArrayEquals(primesTill4, SieveOfEratosthenes.findPrimesTill(3)); - assertArrayEquals(primesTill4, SieveOfEratosthenes.findPrimesTill(4)); + void testPrimesUpTo0() { + assertTrue(SieveOfEratosthenes.findPrimes(0).isEmpty()); } @Test - public void testfFindPrimesTill40() { - var primesTill40 = new int[] {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}; - assertArrayEquals(primesTill40, SieveOfEratosthenes.findPrimesTill(37)); - assertArrayEquals(primesTill40, SieveOfEratosthenes.findPrimesTill(38)); - assertArrayEquals(primesTill40, SieveOfEratosthenes.findPrimesTill(39)); - assertArrayEquals(primesTill40, SieveOfEratosthenes.findPrimesTill(40)); + void testNegativeInput() { + assertThrows(IllegalArgumentException.class, () -> { SieveOfEratosthenes.findPrimes(-1); }); } @Test - public void testfFindPrimesTill240() { - var primesTill240 = new int[] {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239}; - assertArrayEquals(primesTill240, SieveOfEratosthenes.findPrimesTill(239)); - assertArrayEquals(primesTill240, SieveOfEratosthenes.findPrimesTill(240)); + void testCountPrimes() { + assertEquals(4, SieveOfEratosthenes.countPrimes(10)); + assertEquals(25, SieveOfEratosthenes.countPrimes(100)); } @Test - public void testFindPrimesTillThrowsExceptionForNonPositiveInput() { - assertThrows(IllegalArgumentException.class, () -> SieveOfEratosthenes.findPrimesTill(0)); + void testLargeNumber() { + List primes = SieveOfEratosthenes.findPrimes(1000); + assertEquals(168, primes.size()); // There are 168 primes up to 1000 + assertEquals(2, primes.get(0)); // First prime + assertEquals(997, primes.get(primes.size() - 1)); // Last prime up to 1000 } } From cff5d3662e5446ff3371adcb5278ccb2085c956f Mon Sep 17 00:00:00 2001 From: SeungHyeok Yun <162292720+SeungHyeokYoon@users.noreply.github.com> Date: Mon, 17 Nov 2025 03:49:30 +0900 Subject: [PATCH 43/74] feat: add IndexedPriorityQueue implementation and tests (#7062) * feat: add IndexedPriorityQueue implementation and tests * mod : clang-format * Fix Checkstyle naming for IndexedPriorityQueue tests * Align IndexedPriorityQueue tests with Checkstyle and clang-format --- .../heaps/IndexedPriorityQueue.java | 327 ++++++++++++++++ .../heaps/IndexedPriorityQueueTest.java | 350 ++++++++++++++++++ 2 files changed, 677 insertions(+) create mode 100644 src/main/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueue.java create mode 100644 src/test/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueueTest.java diff --git a/src/main/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueue.java b/src/main/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueue.java new file mode 100644 index 000000000000..ad7229760fd0 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueue.java @@ -0,0 +1,327 @@ +package com.thealgorithms.datastructures.heaps; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.IdentityHashMap; +import java.util.Objects; +import java.util.function.Consumer; + +/** + * An addressable (indexed) min-priority queue with O(log n) updates. + * + *

Key features: + *

    + *
  • Each element E is tracked by a handle (its current heap index) via a map, + * enabling O(log n) {@code remove(e)} and O(log n) key updates + * ({@code changeKey/decreaseKey/increaseKey}).
  • + *
  • The queue order is determined by the provided {@link Comparator}. If the + * comparator is {@code null}, elements must implement {@link Comparable} + * (same contract as {@link java.util.PriorityQueue}).
  • + *
  • By default this implementation uses {@link IdentityHashMap} for the index + * mapping to avoid issues with duplicate-equals elements or mutable equals/hashCode. + * If you need value-based equality, switch to {@code HashMap} and read the caveats + * in the class-level Javadoc carefully.
  • + *
+ * + *

IMPORTANT contracts

+ *
    + *
  • Do not mutate comparator-relevant fields of an element directly while it is + * inside the queue. Always use {@code changeKey}/{@code decreaseKey}/{@code increaseKey} + * so the heap can be restored accordingly.
  • + *
  • If you replace {@link IdentityHashMap} with {@link HashMap}, you must ensure: + * (a) no two distinct elements are {@code equals()}-equal at the same time in the queue, and + * (b) {@code equals/hashCode} of elements remain stable while enqueued.
  • + *
  • {@code peek()} returns {@code null} when empty (matching {@link java.util.PriorityQueue}).
  • + *
  • Not thread-safe.
  • + *
+ * + *

Complexities: + * {@code offer, poll, remove(e), changeKey, decreaseKey, increaseKey} are O(log n); + * {@code peek, isEmpty, size, contains} are O(1). + */ +public class IndexedPriorityQueue { + + /** Binary heap storage (min-heap). */ + private Object[] heap; + + /** Number of elements in the heap. */ + private int size; + + /** Comparator used for ordering; if null, elements must be Comparable. */ + private final Comparator cmp; + + /** + * Index map: element -> current heap index. + *

We use IdentityHashMap by default to: + *

    + *
  • allow duplicate-equals elements;
  • + *
  • avoid corruption when equals/hashCode are mutable or not ID-based.
  • + *
+ * If you prefer value-based semantics, replace with HashMap and + * respect the warnings in the class Javadoc. + */ + private final IdentityHashMap index; + + private static final int DEFAULT_INITIAL_CAPACITY = 11; + + public IndexedPriorityQueue() { + this(DEFAULT_INITIAL_CAPACITY, null); + } + + public IndexedPriorityQueue(Comparator cmp) { + this(DEFAULT_INITIAL_CAPACITY, cmp); + } + + public IndexedPriorityQueue(int initialCapacity, Comparator cmp) { + if (initialCapacity < 1) { + throw new IllegalArgumentException("initialCapacity < 1"); + } + this.heap = new Object[initialCapacity]; + this.cmp = cmp; + this.index = new IdentityHashMap<>(); + } + + /** Returns current number of elements. */ + public int size() { + return size; + } + + /** Returns {@code true} if empty. */ + public boolean isEmpty() { + return size == 0; + } + + /** + * Returns the minimum element without removing it, or {@code null} if empty. + * Matches {@link java.util.PriorityQueue#peek()} behavior. + */ + @SuppressWarnings("unchecked") + public E peek() { + return size == 0 ? null : (E) heap[0]; + } + + /** + * Inserts the specified element (O(log n)). + * @throws NullPointerException if {@code e} is null + * @throws ClassCastException if {@code cmp == null} and {@code e} is not Comparable, + * or if incompatible with other elements + */ + public boolean offer(E e) { + Objects.requireNonNull(e, "element is null"); + if (size >= heap.length) { + grow(size + 1); + } + // Insert at the end and bubble up. siftUp will maintain 'index' for all touched nodes. + siftUp(size, e); + size++; + return true; + } + + /** + * Removes and returns the minimum element (O(log n)), or {@code null} if empty. + */ + @SuppressWarnings("unchecked") + public E poll() { + if (size == 0) { + return null; + } + E min = (E) heap[0]; + removeAt(0); // updates map and heap structure + return min; + } + + /** + * Removes one occurrence of the specified element e (O(log n)) if present. + * Uses the index map for O(1) lookup. + */ + public boolean remove(Object o) { + Integer i = index.get(o); + if (i == null) { + return false; + } + removeAt(i); + return true; + } + + /** O(1): returns whether the queue currently contains the given element reference. */ + public boolean contains(Object o) { + return index.containsKey(o); + } + + /** Clears the heap and the index map. */ + public void clear() { + Arrays.fill(heap, 0, size, null); + index.clear(); + size = 0; + } + + // ------------------------------------------------------------------------------------ + // Key update API + // ------------------------------------------------------------------------------------ + + /** + * Changes comparator-relevant fields of {@code e} via the provided {@code mutator}, + * then restores the heap in O(log n) by bubbling in the correct direction. + * + *

IMPORTANT: The mutator must not change {@code equals/hashCode} of {@code e} + * if you migrate this implementation to value-based indexing (HashMap). + * + * @throws IllegalArgumentException if {@code e} is not in the queue + */ + public void changeKey(E e, Consumer mutator) { + Integer i = index.get(e); + if (i == null) { + throw new IllegalArgumentException("Element not in queue"); + } + // Mutate fields used by comparator (do NOT mutate equality/hash if using value-based map) + mutator.accept(e); + // Try bubbling up; if no movement occurred, bubble down. + if (!siftUp(i)) { + siftDown(i); + } + } + + /** + * Faster variant if the new key is strictly smaller (higher priority). + * Performs a single sift-up (O(log n)). + */ + public void decreaseKey(E e, Consumer mutator) { + Integer i = index.get(e); + if (i == null) { + throw new IllegalArgumentException("Element not in queue"); + } + mutator.accept(e); + siftUp(i); + } + + /** + * Faster variant if the new key is strictly larger (lower priority). + * Performs a single sift-down (O(log n)). + */ + public void increaseKey(E e, Consumer mutator) { + Integer i = index.get(e); + if (i == null) { + throw new IllegalArgumentException("Element not in queue"); + } + mutator.accept(e); + siftDown(i); + } + + // ------------------------------------------------------------------------------------ + // Internal utilities + // ------------------------------------------------------------------------------------ + + /** Grows the internal array to accommodate at least {@code minCapacity}. */ + private void grow(int minCapacity) { + int old = heap.length; + int pref = (old < 64) ? old + 2 : old + (old >> 1); // +2 if small, else +50% + int newCap = Math.max(minCapacity, pref); + heap = Arrays.copyOf(heap, newCap); + } + + @SuppressWarnings("unchecked") + private int compare(E a, E b) { + if (cmp != null) { + return cmp.compare(a, b); + } + return ((Comparable) a).compareTo(b); + } + + /** + * Inserts item {@code x} at position {@code k}, bubbling up while maintaining the heap. + * Also maintains the index map for all moved elements. + */ + @SuppressWarnings("unchecked") + private void siftUp(int k, E x) { + while (k > 0) { + int p = (k - 1) >>> 1; + E e = (E) heap[p]; + if (compare(x, e) >= 0) { + break; + } + heap[k] = e; + index.put(e, k); + k = p; + } + heap[k] = x; + index.put(x, k); + } + + /** + * Attempts to bubble up the element currently at {@code k}. + * @return true if it moved; false otherwise. + */ + @SuppressWarnings("unchecked") + private boolean siftUp(int k) { + int orig = k; + E x = (E) heap[k]; + while (k > 0) { + int p = (k - 1) >>> 1; + E e = (E) heap[p]; + if (compare(x, e) >= 0) { + break; + } + heap[k] = e; + index.put(e, k); + k = p; + } + if (k != orig) { + heap[k] = x; + index.put(x, k); + return true; + } + return false; + } + + /** Bubbles down the element currently at {@code k}. */ + @SuppressWarnings("unchecked") + private void siftDown(int k) { + int n = size; + E x = (E) heap[k]; + int half = n >>> 1; // loop while k has at least one child + while (k < half) { + int child = (k << 1) + 1; // assume left is smaller + E c = (E) heap[child]; + int r = child + 1; + if (r < n && compare(c, (E) heap[r]) > 0) { + child = r; + c = (E) heap[child]; + } + if (compare(x, c) <= 0) { + break; + } + heap[k] = c; + index.put(c, k); + k = child; + } + heap[k] = x; + index.put(x, k); + } + + /** + * Removes the element at heap index {@code i}, restoring the heap afterwards. + *

Returns nothing; the standard {@code PriorityQueue} returns a displaced + * element in a rare case to help its iterator. We don't need that here, so + * we keep the API simple. + */ + @SuppressWarnings("unchecked") + private void removeAt(int i) { + int n = --size; // last index after removal + E moved = (E) heap[n]; + E removed = (E) heap[i]; + heap[n] = null; // help GC + index.remove(removed); // drop mapping for removed element + + if (i == n) { + return; // removed last element; done + } + + heap[i] = moved; + index.put(moved, i); + + // Try sift-up first (cheap if key decreased); if no movement, sift-down. + if (!siftUp(i)) { + siftDown(i); + } + } +} diff --git a/src/test/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueueTest.java b/src/test/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueueTest.java new file mode 100644 index 000000000000..8d8c4e1db6bd --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueueTest.java @@ -0,0 +1,350 @@ +package com.thealgorithms.datastructures.heaps; + +import java.util.Comparator; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * Tests for {@link IndexedPriorityQueue}. + * + * Notes: + * - We mainly use a Node class with a mutable "prio" field to test changeKey/decreaseKey/increaseKey. + * - The queue is a min-heap, so smaller "prio" means higher priority. + * - By default the implementation uses IdentityHashMap so duplicate-equals objects are allowed. + */ +public class IndexedPriorityQueueTest { + + // ------------------------ + // Helpers + // ------------------------ + + /** Simple payload with mutable priority. */ + static class Node { + final String id; + int prio; // lower is better (min-heap) + + Node(String id, int prio) { + this.id = id; + this.prio = prio; + } + + @Override + public String toString() { + return id + "(" + prio + ")"; + } + } + + /** Same as Node but overrides equals/hashCode to simulate "duplicate-equals" scenario. */ + static class NodeWithEquals { + final String id; + int prio; + + NodeWithEquals(String id, int prio) { + this.id = id; + this.prio = prio; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof NodeWithEquals)) { + return false; + } + NodeWithEquals other = (NodeWithEquals) o; + // Intentionally naive equality: equal if priority is equal + return this.prio == other.prio; + } + + @Override + public int hashCode() { + return Integer.hashCode(prio); + } + + @Override + public String toString() { + return id + "(" + prio + ")"; + } + } + + private static IndexedPriorityQueue newNodePQ() { + return new IndexedPriorityQueue<>(Comparator.comparingInt(n -> n.prio)); + } + + // ------------------------ + // Basic operations + // ------------------------ + + @Test + void testOfferPollWithIntegersComparableMode() { + // cmp == null -> elements must be Comparable + IndexedPriorityQueue pq = new IndexedPriorityQueue<>(); + Assertions.assertTrue(pq.isEmpty()); + + pq.offer(5); + pq.offer(1); + pq.offer(3); + + Assertions.assertEquals(3, pq.size()); + Assertions.assertEquals(1, pq.peek()); + Assertions.assertEquals(1, pq.poll()); + Assertions.assertEquals(3, pq.poll()); + Assertions.assertEquals(5, pq.poll()); + Assertions.assertNull(pq.poll()); // empty -> null + Assertions.assertTrue(pq.isEmpty()); + } + + @Test + void testPeekAndIsEmpty() { + IndexedPriorityQueue pq = newNodePQ(); + Assertions.assertTrue(pq.isEmpty()); + Assertions.assertNull(pq.peek()); + + pq.offer(new Node("A", 10)); + pq.offer(new Node("B", 5)); + pq.offer(new Node("C", 7)); + + Assertions.assertFalse(pq.isEmpty()); + Assertions.assertEquals("B(5)", pq.peek().toString()); + } + + @Test + void testRemoveSpecificElement() { + IndexedPriorityQueue pq = newNodePQ(); + Node a = new Node("A", 10); + Node b = new Node("B", 5); + Node c = new Node("C", 7); + + pq.offer(a); + pq.offer(b); + pq.offer(c); + + // remove by reference (O(log n)) + Assertions.assertTrue(pq.remove(b)); + Assertions.assertEquals(2, pq.size()); + // now min should be C(7) + Assertions.assertEquals("C(7)", pq.peek().toString()); + // removing an element not present -> false + Assertions.assertFalse(pq.remove(b)); + } + + @Test + void testContainsAndClear() { + IndexedPriorityQueue pq = newNodePQ(); + Node a = new Node("A", 2); + Node b = new Node("B", 3); + + pq.offer(a); + pq.offer(b); + + Assertions.assertTrue(pq.contains(a)); + Assertions.assertTrue(pq.contains(b)); + + pq.clear(); + Assertions.assertTrue(pq.isEmpty()); + Assertions.assertFalse(pq.contains(a)); + Assertions.assertNull(pq.peek()); + } + + // ------------------------ + // Key updates + // ------------------------ + + @Test + void testDecreaseKeyMovesUp() { + IndexedPriorityQueue pq = newNodePQ(); + Node a = new Node("A", 10); + Node b = new Node("B", 5); + Node c = new Node("C", 7); + + pq.offer(a); + pq.offer(b); + pq.offer(c); + + // current min is B(5) + Assertions.assertEquals("B(5)", pq.peek().toString()); + + // Make A more important: 10 -> 1 (smaller is better) + pq.decreaseKey(a, n -> n.prio = 1); + + // Now A should be at the top + Assertions.assertEquals("A(1)", pq.peek().toString()); + } + + @Test + void testIncreaseKeyMovesDown() { + IndexedPriorityQueue pq = newNodePQ(); + Node a = new Node("A", 1); + Node b = new Node("B", 2); + Node c = new Node("C", 3); + + pq.offer(a); + pq.offer(b); + pq.offer(c); + + // min is A(1) + Assertions.assertEquals("A(1)", pq.peek().toString()); + + // Make A worse: 1 -> 100 + pq.increaseKey(a, n -> n.prio = 100); + + // Now min should be B(2) + Assertions.assertEquals("B(2)", pq.peek().toString()); + } + + @Test + void testChangeKeyChoosesDirectionAutomatically() { + IndexedPriorityQueue pq = newNodePQ(); + Node a = new Node("A", 10); + Node b = new Node("B", 20); + Node c = new Node("C", 30); + + pq.offer(a); + pq.offer(b); + pq.offer(c); + + // Decrease B to 0 -> should move up + pq.changeKey(b, n -> n.prio = 0); + Assertions.assertEquals("B(0)", pq.peek().toString()); + + // Increase B to 100 -> should move down + pq.changeKey(b, n -> n.prio = 100); + Assertions.assertEquals("A(10)", pq.peek().toString()); + } + + @Test + void testDirectMutationWithoutChangeKeyDoesNotReheapByDesign() { + // Demonstrates the contract: do NOT mutate comparator fields directly. + IndexedPriorityQueue pq = newNodePQ(); + Node a = new Node("A", 5); + Node b = new Node("B", 10); + + pq.offer(a); + pq.offer(b); + + // Illegally mutate priority directly + a.prio = 100; // worse than b now, but heap wasn't notified + + // The heap structure is unchanged; peek still returns A(100) (was A(5) before) + // This test documents the behavior/contract rather than relying on it. + Assertions.assertEquals("A(100)", pq.peek().toString()); + + // Now fix properly via changeKey (no change in value, but triggers reheap) + pq.changeKey(a, n -> n.prio = n.prio); + Assertions.assertEquals("B(10)", pq.peek().toString()); + } + + // ------------------------ + // Identity semantics & duplicates + // ------------------------ + + @Test + void testDuplicateEqualsElementsAreSupportedIdentityMap() { + IndexedPriorityQueue pq = new IndexedPriorityQueue<>(Comparator.comparingInt(n -> n.prio)); + + NodeWithEquals x1 = new NodeWithEquals("X1", 7); + NodeWithEquals x2 = new NodeWithEquals("X2", 7); // equals to X1 by prio, but different instance + + // With IdentityHashMap internally, both can coexist + pq.offer(x1); + pq.offer(x2); + + Assertions.assertEquals(2, pq.size()); + // Poll twice; both 7s should be returned (order between x1/x2 is unspecified) + Assertions.assertEquals(7, pq.poll().prio); + Assertions.assertEquals(7, pq.poll().prio); + Assertions.assertTrue(pq.isEmpty()); + } + + // ------------------------ + // Capacity growth + // ------------------------ + + @Test + void testGrowByManyInserts() { + IndexedPriorityQueue pq = new IndexedPriorityQueue<>(); + int n = 100; // beyond default capacity (11) + + for (int i = n; i >= 1; i--) { + pq.offer(i); + } + + Assertions.assertEquals(n, pq.size()); + // Ensure min-to-max order when polling + for (int expected = 1; expected <= n; expected++) { + Integer v = pq.poll(); + Assertions.assertEquals(expected, v); + } + Assertions.assertTrue(pq.isEmpty()); + Assertions.assertNull(pq.poll()); + } + + // ------------------------ + // remove/contains edge cases + // ------------------------ + + @Test + void testRemoveHeadAndMiddleAndTail() { + IndexedPriorityQueue pq = newNodePQ(); + Node a = new Node("A", 1); + Node b = new Node("B", 2); + Node c = new Node("C", 3); + Node d = new Node("D", 4); + + pq.offer(a); + pq.offer(b); + pq.offer(c); + pq.offer(d); + + // remove head + Assertions.assertTrue(pq.remove(a)); + Assertions.assertFalse(pq.contains(a)); + Assertions.assertEquals("B(2)", pq.peek().toString()); + + // remove middle + Assertions.assertTrue(pq.remove(c)); + Assertions.assertFalse(pq.contains(c)); + Assertions.assertEquals("B(2)", pq.peek().toString()); + + // remove tail (last) + Assertions.assertTrue(pq.remove(d)); + Assertions.assertFalse(pq.contains(d)); + Assertions.assertEquals("B(2)", pq.peek().toString()); + + // remove last remaining + Assertions.assertTrue(pq.remove(b)); + Assertions.assertTrue(pq.isEmpty()); + Assertions.assertNull(pq.peek()); + } + + // ------------------------ + // Error / edge cases for coverage + // ------------------------ + + @Test + void testInvalidInitialCapacityThrows() { + Assertions.assertThrows(IllegalArgumentException.class, () -> new IndexedPriorityQueue(0, Comparator.naturalOrder())); + } + + @Test + void testChangeKeyOnMissingElementThrows() { + IndexedPriorityQueue pq = newNodePQ(); + Node a = new Node("A", 10); + + Assertions.assertThrows(IllegalArgumentException.class, () -> pq.changeKey(a, n -> n.prio = 5)); + } + + @Test + void testDecreaseKeyOnMissingElementThrows() { + IndexedPriorityQueue pq = newNodePQ(); + Node a = new Node("A", 10); + + Assertions.assertThrows(IllegalArgumentException.class, () -> pq.decreaseKey(a, n -> n.prio = 5)); + } + + @Test + void testIncreaseKeyOnMissingElementThrows() { + IndexedPriorityQueue pq = newNodePQ(); + Node a = new Node("A", 10); + + Assertions.assertThrows(IllegalArgumentException.class, () -> pq.increaseKey(a, n -> n.prio = 15)); + } +} From 9f2b675f3e47c49bf4d1623d9d04f95506e2f813 Mon Sep 17 00:00:00 2001 From: GOPISETTI NAVADEEP <2400030007@kluniversity.in> Date: Mon, 17 Nov 2025 14:24:20 +0530 Subject: [PATCH 44/74] feat: add Sudoku Solver using Backtracking (#7073) * feat: add Sudoku Solver using Backtracking (issue #6929) * refactor: remove old Sudoku class from puzzlesandgames package * Remove old Sudoku implementation and its test class --- .../backtracking/SudokuSolver.java | 157 ++++++++++++++++ .../thealgorithms/puzzlesandgames/Sudoku.java | 169 ------------------ .../backtracking/SudokuSolverTest.java | 53 ++++++ .../puzzlesandgames/SudokuTest.java | 38 ---- 4 files changed, 210 insertions(+), 207 deletions(-) create mode 100644 src/main/java/com/thealgorithms/backtracking/SudokuSolver.java delete mode 100644 src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java create mode 100644 src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java delete mode 100644 src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java diff --git a/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java b/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java new file mode 100644 index 000000000000..543fe2d02b50 --- /dev/null +++ b/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java @@ -0,0 +1,157 @@ +package com.thealgorithms.backtracking; + +/** + * Sudoku Solver using Backtracking Algorithm + * Solves a 9x9 Sudoku puzzle by filling empty cells with valid digits (1-9) + * + * @author Navadeep0007 + */ +public final class SudokuSolver { + + private static final int GRID_SIZE = 9; + private static final int SUBGRID_SIZE = 3; + private static final int EMPTY_CELL = 0; + + private SudokuSolver() { + // Utility class, prevent instantiation + } + + /** + * Solves the Sudoku puzzle using backtracking + * + * @param board 9x9 Sudoku board with 0 representing empty cells + * @return true if puzzle is solved, false otherwise + */ + public static boolean solveSudoku(int[][] board) { + if (board == null || board.length != GRID_SIZE) { + return false; + } + + for (int row = 0; row < GRID_SIZE; row++) { + if (board[row].length != GRID_SIZE) { + return false; + } + } + + return solve(board); + } + + /** + * Recursive helper method to solve the Sudoku puzzle + * + * @param board the Sudoku board + * @return true if solution is found, false otherwise + */ + private static boolean solve(int[][] board) { + for (int row = 0; row < GRID_SIZE; row++) { + for (int col = 0; col < GRID_SIZE; col++) { + if (board[row][col] == EMPTY_CELL) { + for (int number = 1; number <= GRID_SIZE; number++) { + if (isValidPlacement(board, row, col, number)) { + board[row][col] = number; + + if (solve(board)) { + return true; + } + + // Backtrack + board[row][col] = EMPTY_CELL; + } + } + return false; + } + } + } + return true; + } + + /** + * Checks if placing a number at given position is valid + * + * @param board the Sudoku board + * @param row row index + * @param col column index + * @param number number to place (1-9) + * @return true if placement is valid, false otherwise + */ + private static boolean isValidPlacement(int[][] board, int row, int col, int number) { + return !isNumberInRow(board, row, number) && !isNumberInColumn(board, col, number) && !isNumberInSubgrid(board, row, col, number); + } + + /** + * Checks if number exists in the given row + * + * @param board the Sudoku board + * @param row row index + * @param number number to check + * @return true if number exists in row, false otherwise + */ + private static boolean isNumberInRow(int[][] board, int row, int number) { + for (int col = 0; col < GRID_SIZE; col++) { + if (board[row][col] == number) { + return true; + } + } + return false; + } + + /** + * Checks if number exists in the given column + * + * @param board the Sudoku board + * @param col column index + * @param number number to check + * @return true if number exists in column, false otherwise + */ + private static boolean isNumberInColumn(int[][] board, int col, int number) { + for (int row = 0; row < GRID_SIZE; row++) { + if (board[row][col] == number) { + return true; + } + } + return false; + } + + /** + * Checks if number exists in the 3x3 subgrid + * + * @param board the Sudoku board + * @param row row index + * @param col column index + * @param number number to check + * @return true if number exists in subgrid, false otherwise + */ + private static boolean isNumberInSubgrid(int[][] board, int row, int col, int number) { + int subgridRowStart = row - row % SUBGRID_SIZE; + int subgridColStart = col - col % SUBGRID_SIZE; + + for (int i = subgridRowStart; i < subgridRowStart + SUBGRID_SIZE; i++) { + for (int j = subgridColStart; j < subgridColStart + SUBGRID_SIZE; j++) { + if (board[i][j] == number) { + return true; + } + } + } + return false; + } + + /** + * Prints the Sudoku board + * + * @param board the Sudoku board + */ + public static void printBoard(int[][] board) { + for (int row = 0; row < GRID_SIZE; row++) { + if (row % SUBGRID_SIZE == 0 && row != 0) { + System.out.println("-----------"); + } + for (int col = 0; col < GRID_SIZE; col++) { + if (col % SUBGRID_SIZE == 0 && col != 0) { + System.out.print("|"); + } + System.out.print(board[row][col]); + } + System.out.println(); + } + } +} diff --git a/src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java b/src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java deleted file mode 100644 index fce665c4de00..000000000000 --- a/src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java +++ /dev/null @@ -1,169 +0,0 @@ -package com.thealgorithms.puzzlesandgames; - -/** - * A class that provides methods to solve Sudoku puzzles of any n x n size - * using a backtracking approach, where n must be a perfect square. - * The algorithm checks for safe number placements in rows, columns, - * and subgrids (which are sqrt(n) x sqrt(n) in size) and recursively solves the puzzle. - * Though commonly used for 9x9 grids, it is adaptable to other valid Sudoku dimensions. - */ -final class Sudoku { - - private Sudoku() { - } - - /** - * Checks if placing a number in a specific position on the Sudoku board is safe. - * The number is considered safe if it does not violate any of the Sudoku rules: - * - It should not be present in the same row. - * - It should not be present in the same column. - * - It should not be present in the corresponding 3x3 subgrid. - * - It should not be present in the corresponding subgrid, which is sqrt(n) x sqrt(n) in size (e.g., for a 9x9 grid, the subgrid will be 3x3). - * - * @param board The current state of the Sudoku board. - * @param row The row index where the number is to be placed. - * @param col The column index where the number is to be placed. - * @param num The number to be placed on the board. - * @return True if the placement is safe, otherwise false. - */ - public static boolean isSafe(int[][] board, int row, int col, int num) { - // Check the row for duplicates - for (int d = 0; d < board.length; d++) { - if (board[row][d] == num) { - return false; - } - } - - // Check the column for duplicates - for (int r = 0; r < board.length; r++) { - if (board[r][col] == num) { - return false; - } - } - - // Check the corresponding 3x3 subgrid for duplicates - int sqrt = (int) Math.sqrt(board.length); - int boxRowStart = row - row % sqrt; - int boxColStart = col - col % sqrt; - - for (int r = boxRowStart; r < boxRowStart + sqrt; r++) { - for (int d = boxColStart; d < boxColStart + sqrt; d++) { - if (board[r][d] == num) { - return false; - } - } - } - - return true; - } - - /** - * Solves the Sudoku puzzle using backtracking. - * The algorithm finds an empty cell and tries placing numbers - * from 1 to n, where n is the size of the board - * (for example, from 1 to 9 in a standard 9x9 Sudoku). - * The algorithm finds an empty cell and tries placing numbers from 1 to 9. - * The standard version of Sudoku uses numbers from 1 to 9, so the algorithm can be - * easily modified for other variations of the game. - * If a number placement is valid (checked via `isSafe`), the number is - * placed and the function recursively attempts to solve the rest of the puzzle. - * If no solution is possible, the number is removed (backtracked), - * and the process is repeated. - * - * @param board The current state of the Sudoku board. - * @param n The size of the Sudoku board (typically 9 for a standard puzzle). - * @return True if the Sudoku puzzle is solvable, false otherwise. - */ - public static boolean solveSudoku(int[][] board, int n) { - int row = -1; - int col = -1; - boolean isEmpty = true; - - // Find the next empty cell - for (int i = 0; i < n; i++) { - for (int j = 0; j < n; j++) { - if (board[i][j] == 0) { - row = i; - col = j; - isEmpty = false; - break; - } - } - if (!isEmpty) { - break; - } - } - - // No empty space left - if (isEmpty) { - return true; - } - - // Try placing numbers 1 to n in the empty cell (n should be a perfect square) - // Eg: n=9 for a standard 9x9 Sudoku puzzle, n=16 for a 16x16 puzzle, etc. - for (int num = 1; num <= n; num++) { - if (isSafe(board, row, col, num)) { - board[row][col] = num; - if (solveSudoku(board, n)) { - return true; - } else { - // replace it - board[row][col] = 0; - } - } - } - return false; - } - - /** - * Prints the current state of the Sudoku board in a readable format. - * Each row is printed on a new line, with numbers separated by spaces. - * - * @param board The current state of the Sudoku board. - * @param n The size of the Sudoku board (typically 9 for a standard puzzle). - */ - public static void print(int[][] board, int n) { - // Print the board in a nxn grid format - // if n=9, print the board in a 9x9 grid format - // if n=16, print the board in a 16x16 grid format - for (int r = 0; r < n; r++) { - for (int d = 0; d < n; d++) { - System.out.print(board[r][d]); - System.out.print(" "); - } - System.out.print("\n"); - - if ((r + 1) % (int) Math.sqrt(n) == 0) { - System.out.print(""); - } - } - } - - /** - * The driver method to demonstrate solving a Sudoku puzzle. - * A sample 9x9 Sudoku puzzle is provided, and the program attempts to solve it - * using the `solveSudoku` method. If a solution is found, it is printed to the console. - * - * @param args Command-line arguments (not used in this program). - */ - public static void main(String[] args) { - int[][] board = new int[][] { - {3, 0, 6, 5, 0, 8, 4, 0, 0}, - {5, 2, 0, 0, 0, 0, 0, 0, 0}, - {0, 8, 7, 0, 0, 0, 0, 3, 1}, - {0, 0, 3, 0, 1, 0, 0, 8, 0}, - {9, 0, 0, 8, 6, 3, 0, 0, 5}, - {0, 5, 0, 0, 9, 0, 6, 0, 0}, - {1, 3, 0, 0, 0, 0, 2, 5, 0}, - {0, 0, 0, 0, 0, 0, 0, 7, 4}, - {0, 0, 5, 2, 0, 6, 3, 0, 0}, - }; - int n = board.length; - - if (solveSudoku(board, n)) { - print(board, n); - } else { - System.out.println("No solution"); - } - } -} diff --git a/src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java b/src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java new file mode 100644 index 000000000000..75d3eae08629 --- /dev/null +++ b/src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java @@ -0,0 +1,53 @@ +package com.thealgorithms.backtracking; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class SudokuSolverTest { + + @Test + void testSolveSudokuEasyPuzzle() { + int[][] board = {{5, 3, 0, 0, 7, 0, 0, 0, 0}, {6, 0, 0, 1, 9, 5, 0, 0, 0}, {0, 9, 8, 0, 0, 0, 0, 6, 0}, {8, 0, 0, 0, 6, 0, 0, 0, 3}, {4, 0, 0, 8, 0, 3, 0, 0, 1}, {7, 0, 0, 0, 2, 0, 0, 0, 6}, {0, 6, 0, 0, 0, 0, 2, 8, 0}, {0, 0, 0, 4, 1, 9, 0, 0, 5}, {0, 0, 0, 0, 8, 0, 0, 7, 9}}; + + assertTrue(SudokuSolver.solveSudoku(board)); + + int[][] expected = {{5, 3, 4, 6, 7, 8, 9, 1, 2}, {6, 7, 2, 1, 9, 5, 3, 4, 8}, {1, 9, 8, 3, 4, 2, 5, 6, 7}, {8, 5, 9, 7, 6, 1, 4, 2, 3}, {4, 2, 6, 8, 5, 3, 7, 9, 1}, {7, 1, 3, 9, 2, 4, 8, 5, 6}, {9, 6, 1, 5, 3, 7, 2, 8, 4}, {2, 8, 7, 4, 1, 9, 6, 3, 5}, {3, 4, 5, 2, 8, 6, 1, 7, 9}}; + + assertArrayEquals(expected, board); + } + + @Test + void testSolveSudokuHardPuzzle() { + int[][] board = {{0, 0, 0, 0, 0, 0, 6, 8, 0}, {0, 0, 0, 0, 7, 3, 0, 0, 9}, {3, 0, 9, 0, 0, 0, 0, 4, 5}, {4, 9, 0, 0, 0, 0, 0, 0, 0}, {8, 0, 3, 0, 5, 0, 9, 0, 2}, {0, 0, 0, 0, 0, 0, 0, 3, 6}, {9, 6, 0, 0, 0, 0, 3, 0, 8}, {7, 0, 0, 6, 8, 0, 0, 0, 0}, {0, 2, 8, 0, 0, 0, 0, 0, 0}}; + + assertTrue(SudokuSolver.solveSudoku(board)); + } + + @Test + void testSolveSudokuAlreadySolved() { + int[][] board = {{5, 3, 4, 6, 7, 8, 9, 1, 2}, {6, 7, 2, 1, 9, 5, 3, 4, 8}, {1, 9, 8, 3, 4, 2, 5, 6, 7}, {8, 5, 9, 7, 6, 1, 4, 2, 3}, {4, 2, 6, 8, 5, 3, 7, 9, 1}, {7, 1, 3, 9, 2, 4, 8, 5, 6}, {9, 6, 1, 5, 3, 7, 2, 8, 4}, {2, 8, 7, 4, 1, 9, 6, 3, 5}, {3, 4, 5, 2, 8, 6, 1, 7, 9}}; + + assertTrue(SudokuSolver.solveSudoku(board)); + } + + @Test + void testSolveSudokuInvalidSize() { + int[][] board = {{1, 2, 3}, {4, 5, 6}}; + assertFalse(SudokuSolver.solveSudoku(board)); + } + + @Test + void testSolveSudokuNullBoard() { + assertFalse(SudokuSolver.solveSudoku(null)); + } + + @Test + void testSolveSudokuEmptyBoard() { + int[][] board = {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}}; + + assertTrue(SudokuSolver.solveSudoku(board)); + } +} diff --git a/src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java b/src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java deleted file mode 100644 index 7fb96dcf805f..000000000000 --- a/src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.thealgorithms.puzzlesandgames; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.junit.jupiter.api.Test; - -public class SudokuTest { - - @Test - void testIsSafe2() { - int[][] board = {{3, 0, 6, 5, 0, 8, 4, 0, 0}, {5, 2, 0, 0, 0, 0, 0, 0, 0}, {0, 8, 7, 0, 0, 0, 0, 3, 1}, {0, 0, 3, 0, 1, 0, 0, 8, 0}, {9, 0, 0, 8, 6, 3, 0, 0, 5}, {0, 5, 0, 0, 9, 0, 6, 0, 0}, {1, 3, 0, 0, 0, 0, 2, 5, 0}, {0, 0, 0, 0, 0, 0, 0, 7, 4}, {0, 0, 5, 2, 0, 6, 3, 0, 0}}; - - assertFalse(Sudoku.isSafe(board, 0, 1, 3)); - assertTrue(Sudoku.isSafe(board, 1, 2, 1)); - assertThrows(ArrayIndexOutOfBoundsException.class, () -> { Sudoku.isSafe(board, 10, 10, 5); }); - assertThrows(ArrayIndexOutOfBoundsException.class, () -> { Sudoku.isSafe(board, -1, 0, 5); }); - } - - @Test - void testSolveSudoku() { - int[][] board = {{3, 0, 6, 5, 0, 8, 4, 0, 0}, {5, 2, 0, 0, 0, 0, 0, 0, 0}, {0, 8, 7, 0, 0, 0, 0, 3, 1}, {0, 0, 3, 0, 1, 0, 0, 8, 0}, {9, 0, 0, 8, 6, 3, 0, 0, 5}, {0, 5, 0, 0, 9, 0, 6, 0, 0}, {1, 3, 0, 0, 0, 0, 2, 5, 0}, {0, 0, 0, 0, 0, 0, 0, 7, 4}, {0, 0, 5, 2, 0, 6, 3, 0, 0}}; - - assertTrue(Sudoku.solveSudoku(board, board.length)); - assertEquals(1, board[0][1]); - assertThrows(ArrayIndexOutOfBoundsException.class, () -> { Sudoku.solveSudoku(board, 10); }); - assertTrue(Sudoku.solveSudoku(board, -1)); - } - - @Test - void testUnsolvableSudoku() { - int[][] unsolvableBoard = {{5, 1, 6, 8, 4, 9, 7, 3, 2}, {3, 0, 7, 6, 0, 5, 0, 0, 0}, {8, 0, 9, 7, 0, 0, 0, 6, 5}, {1, 3, 5, 0, 6, 0, 9, 0, 7}, {4, 7, 2, 5, 9, 1, 0, 0, 6}, {9, 6, 8, 3, 7, 0, 0, 5, 0}, {2, 5, 3, 1, 8, 6, 0, 7, 4}, {6, 8, 4, 2, 5, 7, 3, 9, 0}, {7, 9, 1, 4, 3, 0, 5, 0, 0}}; - - assertFalse(Sudoku.solveSudoku(unsolvableBoard, unsolvableBoard.length)); - } -} From 1c97ad8015855780e7d86248dd2938ef38caf2d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Nov 2025 22:16:07 +0100 Subject: [PATCH 45/74] chore(deps): bump org.apache.commons:commons-lang3 from 3.19.0 to 3.20.0 (#7076) Bumps org.apache.commons:commons-lang3 from 3.19.0 to 3.20.0. --- updated-dependencies: - dependency-name: org.apache.commons:commons-lang3 dependency-version: 3.20.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6126bbe4d6c5..774db2ec4403 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ org.apache.commons commons-lang3 - 3.19.0 + 3.20.0 org.apache.commons From 3519e396af269683a42796ef653b37abdcd7d791 Mon Sep 17 00:00:00 2001 From: shreeya-g10 Date: Wed, 19 Nov 2025 21:50:46 +0530 Subject: [PATCH 46/74] backtracking: add unique permutation algorithm with test cases (#7078) * Add unique permutation algorithm and test cases * Fix: add braces for checkstyle * Apply clang-format --- .../backtracking/UniquePermutation.java | 62 +++++++++++++++++++ .../backtracking/UniquePermutationTest.java | 31 ++++++++++ 2 files changed, 93 insertions(+) create mode 100644 src/main/java/com/thealgorithms/backtracking/UniquePermutation.java create mode 100644 src/test/java/com/thealgorithms/backtracking/UniquePermutationTest.java diff --git a/src/main/java/com/thealgorithms/backtracking/UniquePermutation.java b/src/main/java/com/thealgorithms/backtracking/UniquePermutation.java new file mode 100644 index 000000000000..4804e247ab03 --- /dev/null +++ b/src/main/java/com/thealgorithms/backtracking/UniquePermutation.java @@ -0,0 +1,62 @@ +package com.thealgorithms.backtracking; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Generates all UNIQUE permutations of a string, even when duplicate characters exist. + * + * Example: + * Input: "AAB" + * Output: ["AAB", "ABA", "BAA"] + * + * Time Complexity: O(n! * n) + */ +public final class UniquePermutation { + + private UniquePermutation() { + // Prevent instantiation + throw new UnsupportedOperationException("Utility class"); + } + + public static List generateUniquePermutations(String input) { + List result = new ArrayList<>(); + if (input == null) { + return result; + } + + char[] chars = input.toCharArray(); + Arrays.sort(chars); // important: sort to detect duplicates + + backtrack(chars, new boolean[chars.length], new StringBuilder(), result); + return result; + } + + private static void backtrack(char[] chars, boolean[] used, StringBuilder current, List result) { + + if (current.length() == chars.length) { + result.add(current.toString()); + return; + } + + for (int i = 0; i < chars.length; i++) { + + // skip duplicates + if (i > 0 && chars[i] == chars[i - 1] && !used[i - 1]) { + continue; + } + + if (!used[i]) { + used[i] = true; + current.append(chars[i]); + + backtrack(chars, used, current, result); + + // undo changes + used[i] = false; + current.deleteCharAt(current.length() - 1); + } + } + } +} diff --git a/src/test/java/com/thealgorithms/backtracking/UniquePermutationTest.java b/src/test/java/com/thealgorithms/backtracking/UniquePermutationTest.java new file mode 100644 index 000000000000..c8e7cd0af0dd --- /dev/null +++ b/src/test/java/com/thealgorithms/backtracking/UniquePermutationTest.java @@ -0,0 +1,31 @@ +package com.thealgorithms.backtracking; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class UniquePermutationTest { + + @Test + void testUniquePermutationsAab() { + List expected = Arrays.asList("AAB", "ABA", "BAA"); + List result = UniquePermutation.generateUniquePermutations("AAB"); + assertEquals(expected, result); + } + + @Test + void testUniquePermutationsAbc() { + List expected = Arrays.asList("ABC", "ACB", "BAC", "BCA", "CAB", "CBA"); + List result = UniquePermutation.generateUniquePermutations("ABC"); + assertEquals(expected, result); + } + + @Test + void testEmptyString() { + List expected = Arrays.asList(""); + List result = UniquePermutation.generateUniquePermutations(""); + assertEquals(expected, result); + } +} From e37a7ab6ce87c7cf13274366dca536d34cfc5668 Mon Sep 17 00:00:00 2001 From: Deniz Altunkapan Date: Wed, 19 Nov 2025 17:25:09 +0100 Subject: [PATCH 47/74] Update DIRECTORY.md (#7070) Co-authored-by: alxkm --- DIRECTORY.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index f15d65c18c3f..042efa72addc 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -24,6 +24,8 @@ - 📄 [Permutation](src/main/java/com/thealgorithms/backtracking/Permutation.java) - 📄 [PowerSum](src/main/java/com/thealgorithms/backtracking/PowerSum.java) - 📄 [SubsequenceFinder](src/main/java/com/thealgorithms/backtracking/SubsequenceFinder.java) + - 📄 [SudokuSolver](src/main/java/com/thealgorithms/backtracking/SudokuSolver.java) + - 📄 [UniquePermutation](src/main/java/com/thealgorithms/backtracking/UniquePermutation.java) - 📄 [WordPatternMatcher](src/main/java/com/thealgorithms/backtracking/WordPatternMatcher.java) - 📄 [WordSearch](src/main/java/com/thealgorithms/backtracking/WordSearch.java) - 📁 **bitmanipulation** @@ -133,6 +135,7 @@ - 📄 [PhoneticAlphabetConverter](src/main/java/com/thealgorithms/conversions/PhoneticAlphabetConverter.java) - 📄 [RgbHsvConversion](src/main/java/com/thealgorithms/conversions/RgbHsvConversion.java) - 📄 [RomanToInteger](src/main/java/com/thealgorithms/conversions/RomanToInteger.java) + - 📄 [TemperatureConverter](src/main/java/com/thealgorithms/conversions/TemperatureConverter.java) - 📄 [TimeConverter](src/main/java/com/thealgorithms/conversions/TimeConverter.java) - 📄 [TurkishToLatinConversion](src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java) - 📄 [UnitConversions](src/main/java/com/thealgorithms/conversions/UnitConversions.java) @@ -208,6 +211,7 @@ - 📄 [GenericHeap](src/main/java/com/thealgorithms/datastructures/heaps/GenericHeap.java) - 📄 [Heap](src/main/java/com/thealgorithms/datastructures/heaps/Heap.java) - 📄 [HeapElement](src/main/java/com/thealgorithms/datastructures/heaps/HeapElement.java) + - 📄 [IndexedPriorityQueue](src/main/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueue.java) - 📄 [KthElementFinder](src/main/java/com/thealgorithms/datastructures/heaps/KthElementFinder.java) - 📄 [LeftistHeap](src/main/java/com/thealgorithms/datastructures/heaps/LeftistHeap.java) - 📄 [MaxHeap](src/main/java/com/thealgorithms/datastructures/heaps/MaxHeap.java) @@ -507,6 +511,7 @@ - 📄 [PiNilakantha](src/main/java/com/thealgorithms/maths/PiNilakantha.java) - 📄 [PollardRho](src/main/java/com/thealgorithms/maths/PollardRho.java) - 📄 [Pow](src/main/java/com/thealgorithms/maths/Pow.java) + - 📄 [PowerOfFour](src/main/java/com/thealgorithms/maths/PowerOfFour.java) - 📄 [PowerOfTwoOrNot](src/main/java/com/thealgorithms/maths/PowerOfTwoOrNot.java) - 📄 [PowerUsingRecursion](src/main/java/com/thealgorithms/maths/PowerUsingRecursion.java) - 📁 **Prime** @@ -525,6 +530,7 @@ - 📄 [SieveOfAtkin](src/main/java/com/thealgorithms/maths/SieveOfAtkin.java) - 📄 [SieveOfEratosthenes](src/main/java/com/thealgorithms/maths/SieveOfEratosthenes.java) - 📄 [SimpsonIntegration](src/main/java/com/thealgorithms/maths/SimpsonIntegration.java) + - 📄 [SmithNumber](src/main/java/com/thealgorithms/maths/SmithNumber.java) - 📄 [SolovayStrassenPrimalityTest](src/main/java/com/thealgorithms/maths/SolovayStrassenPrimalityTest.java) - 📄 [SquareRootWithBabylonianMethod](src/main/java/com/thealgorithms/maths/SquareRootWithBabylonianMethod.java) - 📄 [SquareRootWithNewtonRaphsonMethod](src/main/java/com/thealgorithms/maths/SquareRootWithNewtonRaphsonMethod.java) @@ -622,7 +628,6 @@ - 📄 [ProjectileMotion](src/main/java/com/thealgorithms/physics/ProjectileMotion.java) - 📄 [SimplePendulumRK4](src/main/java/com/thealgorithms/physics/SimplePendulumRK4.java) - 📁 **puzzlesandgames** - - 📄 [Sudoku](src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java) - 📄 [TowerOfHanoi](src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java) - 📄 [WordBoggle](src/main/java/com/thealgorithms/puzzlesandgames/WordBoggle.java) - 📁 **randomized** @@ -842,6 +847,8 @@ - 📄 [PermutationTest](src/test/java/com/thealgorithms/backtracking/PermutationTest.java) - 📄 [PowerSumTest](src/test/java/com/thealgorithms/backtracking/PowerSumTest.java) - 📄 [SubsequenceFinderTest](src/test/java/com/thealgorithms/backtracking/SubsequenceFinderTest.java) + - 📄 [SudokuSolverTest](src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java) + - 📄 [UniquePermutationTest](src/test/java/com/thealgorithms/backtracking/UniquePermutationTest.java) - 📄 [WordPatternMatcherTest](src/test/java/com/thealgorithms/backtracking/WordPatternMatcherTest.java) - 📄 [WordSearchTest](src/test/java/com/thealgorithms/backtracking/WordSearchTest.java) - 📁 **bitmanipulation** @@ -944,6 +951,7 @@ - 📄 [OctalToHexadecimalTest](src/test/java/com/thealgorithms/conversions/OctalToHexadecimalTest.java) - 📄 [PhoneticAlphabetConverterTest](src/test/java/com/thealgorithms/conversions/PhoneticAlphabetConverterTest.java) - 📄 [RomanToIntegerTest](src/test/java/com/thealgorithms/conversions/RomanToIntegerTest.java) + - 📄 [TemperatureConverterTest](src/test/java/com/thealgorithms/conversions/TemperatureConverterTest.java) - 📄 [TimeConverterTest](src/test/java/com/thealgorithms/conversions/TimeConverterTest.java) - 📄 [TurkishToLatinConversionTest](src/test/java/com/thealgorithms/conversions/TurkishToLatinConversionTest.java) - 📄 [UnitConversionsTest](src/test/java/com/thealgorithms/conversions/UnitConversionsTest.java) @@ -1009,6 +1017,7 @@ - 📄 [FibonacciHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/FibonacciHeapTest.java) - 📄 [GenericHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/GenericHeapTest.java) - 📄 [HeapElementTest](src/test/java/com/thealgorithms/datastructures/heaps/HeapElementTest.java) + - 📄 [IndexedPriorityQueueTest](src/test/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueueTest.java) - 📄 [KthElementFinderTest](src/test/java/com/thealgorithms/datastructures/heaps/KthElementFinderTest.java) - 📄 [LeftistHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/LeftistHeapTest.java) - 📄 [MaxHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/MaxHeapTest.java) @@ -1279,6 +1288,7 @@ - 📄 [PiApproximationTest](src/test/java/com/thealgorithms/maths/PiApproximationTest.java) - 📄 [PollardRhoTest](src/test/java/com/thealgorithms/maths/PollardRhoTest.java) - 📄 [PowTest](src/test/java/com/thealgorithms/maths/PowTest.java) + - 📄 [PowerOfFourTest](src/test/java/com/thealgorithms/maths/PowerOfFourTest.java) - 📄 [PowerOfTwoOrNotTest](src/test/java/com/thealgorithms/maths/PowerOfTwoOrNotTest.java) - 📄 [PowerUsingRecursionTest](src/test/java/com/thealgorithms/maths/PowerUsingRecursionTest.java) - 📄 [PronicNumberTest](src/test/java/com/thealgorithms/maths/PronicNumberTest.java) @@ -1288,6 +1298,7 @@ - 📄 [SecondMinMaxTest](src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java) - 📄 [SieveOfAtkinTest](src/test/java/com/thealgorithms/maths/SieveOfAtkinTest.java) - 📄 [SieveOfEratosthenesTest](src/test/java/com/thealgorithms/maths/SieveOfEratosthenesTest.java) + - 📄 [SmithNumberTest](src/test/java/com/thealgorithms/maths/SmithNumberTest.java) - 📄 [SolovayStrassenPrimalityTestTest](src/test/java/com/thealgorithms/maths/SolovayStrassenPrimalityTestTest.java) - 📄 [SquareFreeIntegerTest](src/test/java/com/thealgorithms/maths/SquareFreeIntegerTest.java) - 📄 [SquareRootWithNewtonRaphsonTestMethod](src/test/java/com/thealgorithms/maths/SquareRootWithNewtonRaphsonTestMethod.java) @@ -1377,7 +1388,6 @@ - 📄 [ProjectileMotionTest](src/test/java/com/thealgorithms/physics/ProjectileMotionTest.java) - 📄 [SimplePendulumRK4Test](src/test/java/com/thealgorithms/physics/SimplePendulumRK4Test.java) - 📁 **puzzlesandgames** - - 📄 [SudokuTest](src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java) - 📄 [TowerOfHanoiTest](src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java) - 📄 [WordBoggleTest](src/test/java/com/thealgorithms/puzzlesandgames/WordBoggleTest.java) - 📁 **randomized** From fba6292ebc849dc8311ab24d8bcbf6e3dacbc105 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Wed, 19 Nov 2025 19:31:32 +0100 Subject: [PATCH 48/74] chore: pin infer to more recent hash (#7079) * chore: pin infer to more recent hash * chore: suppress new infer warnings --- .github/workflows/infer.yml | 2 +- .inferconfig | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/infer.yml b/.github/workflows/infer.yml index 3df7c4b1fc9e..329fb0cd720a 100644 --- a/.github/workflows/infer.yml +++ b/.github/workflows/infer.yml @@ -44,7 +44,7 @@ jobs: cd .. git clone https://github.com/facebook/infer.git cd infer - git checkout 01aaa268f9d38723ba69c139e10f9e2a04b40b1c + git checkout 02c2c43b71e4c5110c0be841e66153942fda06c9 ./build-infer.sh java cp -r infer ../Java diff --git a/.inferconfig b/.inferconfig index 6af4f9e2e818..239172177b38 100644 --- a/.inferconfig +++ b/.inferconfig @@ -1,6 +1,8 @@ { "report-block-list-path-regex": [ "src/main/java/com/thealgorithms/ciphers/a5/CompositeLFSR.java", + "src/main/java/com/thealgorithms/compression/ArithmeticCoding.java", + "src/main/java/com/thealgorithms/datastructures/caches/FIFOCache.java", "src/main/java/com/thealgorithms/datastructures/crdt/GCounter.java", "src/main/java/com/thealgorithms/datastructures/crdt/PNCounter.java", "src/main/java/com/thealgorithms/datastructures/graphs/KahnsAlgorithm.java", @@ -8,15 +10,18 @@ "src/main/java/com/thealgorithms/datastructures/lists/DoublyLinkedList.java", "src/main/java/com/thealgorithms/datastructures/trees/CreateBinaryTreeFromInorderPreorder.java", "src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java", + "src/main/java/com/thealgorithms/dynamicprogramming/DamerauLevenshteinDistance.java", "src/main/java/com/thealgorithms/dynamicprogramming/Fibonacci.java", "src/main/java/com/thealgorithms/maths/SimpsonIntegration.java", "src/main/java/com/thealgorithms/others/Dijkstra.java", "src/main/java/com/thealgorithms/sorts/TopologicalSort.java", "src/main/java/com/thealgorithms/strings/AhoCorasick.java", + "src/test/java/com/thealgorithms/compression/ShannonFanoTest.java", "src/test/java/com/thealgorithms/datastructures/caches/LRUCacheTest.java", "src/test/java/com/thealgorithms/datastructures/lists/SkipListTest.java", "src/test/java/com/thealgorithms/datastructures/trees/KDTreeTest.java", "src/test/java/com/thealgorithms/datastructures/trees/LazySegmentTreeTest.java", + "src/test/java/com/thealgorithms/others/HuffmanTest.java", "src/test/java/com/thealgorithms/searches/QuickSelectTest.java", "src/test/java/com/thealgorithms/stacks/PostfixToInfixTest.java", "src/test/java/com/thealgorithms/strings/HorspoolSearchTest.java" From e6c576c50aac098f84a1e6a02d81c714750100ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 19:44:44 +0100 Subject: [PATCH 49/74] chore(deps): bump actions/checkout from 5 to 6 in /.github/workflows (#7084) Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 2 +- .github/workflows/clang-format-lint.yml | 2 +- .github/workflows/codeql.yml | 4 ++-- .github/workflows/infer.yml | 2 +- .github/workflows/project_structure.yml | 2 +- .github/workflows/update-directorymd.yml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 39bde758d68e..c5f200c12836 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Set up JDK uses: actions/setup-java@v5 with: diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index ca014e115282..dc0c9754ed1b 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: DoozyX/clang-format-lint-action@v0.20 with: source: './src' diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 3a4cfd829b6b..152d0d766fd2 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up JDK uses: actions/setup-java@v5 @@ -52,7 +52,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Initialize CodeQL uses: github/codeql-action/init@v4 diff --git a/.github/workflows/infer.yml b/.github/workflows/infer.yml index 329fb0cd720a..c85b1d225f72 100644 --- a/.github/workflows/infer.yml +++ b/.github/workflows/infer.yml @@ -15,7 +15,7 @@ jobs: run_infer: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Set up JDK uses: actions/setup-java@v5 diff --git a/.github/workflows/project_structure.yml b/.github/workflows/project_structure.yml index f9fb82a2781c..5aadc6353791 100644 --- a/.github/workflows/project_structure.yml +++ b/.github/workflows/project_structure.yml @@ -15,7 +15,7 @@ jobs: check_structure: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-python@v6 with: python-version: '3.13' diff --git a/.github/workflows/update-directorymd.yml b/.github/workflows/update-directorymd.yml index 6692a884a867..f6c91abe0e74 100644 --- a/.github/workflows/update-directorymd.yml +++ b/.github/workflows/update-directorymd.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Run Directory Tree Generator uses: DenizAltunkapan/directory-tree-generator@v2 From fa8ea8e6143ee788eb752178b2252faa41e546cf Mon Sep 17 00:00:00 2001 From: KANAKALA SAI KIRAN <2400030639@kluniversity.in> Date: Sat, 22 Nov 2025 15:14:34 +0530 Subject: [PATCH 50/74] Feature/centroid decomposition (#7086) * feat: Add Centroid Decomposition for trees (#7054) - Implement CentroidDecomposition with O(N log N) construction - Add CentroidTree class with parent tracking and query methods - Include buildFromEdges helper for easy tree construction - Add comprehensive test suite with 20+ test cases - Cover edge cases, validation, and various tree structures Closes #7054 * feat: Add Centroid Decomposition for trees (#7054) - Implement CentroidDecomposition with O(N log N) construction - Add CentroidTree class with parent tracking and query methods - Include buildFromEdges helper for easy tree construction - Add comprehensive test suite with 20+ test cases - Cover edge cases, validation, and various tree structures Closes #7054 * fix: Remove trailing whitespace from CentroidDecompositionTest * fix: Remove trailing whitespace and add newlines at end of files * fix: Format code to comply with clang-format and checkstyle requirements * style: Fix lambda formatting in test assertions - Change single-line lambdas to multi-line format - Align with repository code style guidelines * style: Apply clang-format to match repository style guide - Format code according to .clang-format configuration - Use single-line lambdas as allowed by AllowShortLambdasOnASingleLine: All - Apply 4-space indentation - Ensure proper line endings --- .../trees/CentroidDecomposition.java | 217 ++++++++++++++++ .../trees/CentroidDecompositionTest.java | 236 ++++++++++++++++++ 2 files changed, 453 insertions(+) create mode 100644 src/main/java/com/thealgorithms/datastructures/trees/CentroidDecomposition.java create mode 100644 src/test/java/com/thealgorithms/datastructures/trees/CentroidDecompositionTest.java diff --git a/src/main/java/com/thealgorithms/datastructures/trees/CentroidDecomposition.java b/src/main/java/com/thealgorithms/datastructures/trees/CentroidDecomposition.java new file mode 100644 index 000000000000..0b29dd6f5f5e --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/trees/CentroidDecomposition.java @@ -0,0 +1,217 @@ +package com.thealgorithms.datastructures.trees; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Centroid Decomposition is a divide-and-conquer technique for trees. + * It recursively partitions a tree by finding centroids - nodes whose removal + * creates balanced subtrees (each with at most N/2 nodes). + * + *

+ * Time Complexity: O(N log N) for construction + * Space Complexity: O(N) + * + *

+ * Applications: + * - Distance queries on trees + * - Path counting problems + * - Nearest neighbor searches + * + * @see Centroid Decomposition + * @see Centroid Decomposition Tutorial + * @author lens161 + */ +public final class CentroidDecomposition { + + private CentroidDecomposition() { + } + + /** + * Represents the centroid tree structure. + */ + public static final class CentroidTree { + private final int n; + private final List> adj; + private final int[] parent; + private final int[] subtreeSize; + private final boolean[] removed; + private int root; + + /** + * Constructs a centroid tree from an adjacency list. + * + * @param adj adjacency list representation of the tree (0-indexed) + * @throws IllegalArgumentException if tree is empty or null + */ + public CentroidTree(List> adj) { + if (adj == null || adj.isEmpty()) { + throw new IllegalArgumentException("Tree cannot be empty or null"); + } + + this.n = adj.size(); + this.adj = adj; + this.parent = new int[n]; + this.subtreeSize = new int[n]; + this.removed = new boolean[n]; + Arrays.fill(parent, -1); + + // Build centroid tree starting from node 0 + this.root = decompose(0, -1); + } + + /** + * Recursively builds the centroid tree. + * + * @param u current node + * @param p parent in centroid tree + * @return centroid of current component + */ + private int decompose(int u, int p) { + int size = getSubtreeSize(u, -1); + int centroid = findCentroid(u, -1, size); + + removed[centroid] = true; + parent[centroid] = p; + + // Recursively decompose each subtree + for (int v : adj.get(centroid)) { + if (!removed[v]) { + decompose(v, centroid); + } + } + + return centroid; + } + + /** + * Calculates subtree size from node u. + * + * @param u current node + * @param p parent node (-1 for root) + * @return size of subtree rooted at u + */ + private int getSubtreeSize(int u, int p) { + subtreeSize[u] = 1; + for (int v : adj.get(u)) { + if (v != p && !removed[v]) { + subtreeSize[u] += getSubtreeSize(v, u); + } + } + return subtreeSize[u]; + } + + /** + * Finds the centroid of a subtree. + * A centroid is a node whose removal creates components with size <= totalSize/2. + * + * @param u current node + * @param p parent node + * @param totalSize total size of current component + * @return centroid node + */ + private int findCentroid(int u, int p, int totalSize) { + for (int v : adj.get(u)) { + if (v != p && !removed[v] && subtreeSize[v] > totalSize / 2) { + return findCentroid(v, u, totalSize); + } + } + return u; + } + + /** + * Gets the parent of a node in the centroid tree. + * + * @param node the node + * @return parent node in centroid tree, or -1 if root + */ + public int getParent(int node) { + if (node < 0 || node >= n) { + throw new IllegalArgumentException("Invalid node: " + node); + } + return parent[node]; + } + + /** + * Gets the root of the centroid tree. + * + * @return root node + */ + public int getRoot() { + return root; + } + + /** + * Gets the number of nodes in the tree. + * + * @return number of nodes + */ + public int size() { + return n; + } + + /** + * Returns the centroid tree structure as a string. + * Format: node -> parent (or ROOT for root node) + * + * @return string representation + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder("Centroid Tree:\n"); + for (int i = 0; i < n; i++) { + sb.append("Node ").append(i).append(" -> "); + if (parent[i] == -1) { + sb.append("ROOT"); + } else { + sb.append("Parent ").append(parent[i]); + } + sb.append("\n"); + } + return sb.toString(); + } + } + + /** + * Creates a centroid tree from an edge list. + * + * @param n number of nodes (0-indexed: 0 to n-1) + * @param edges list of edges where each edge is [u, v] + * @return CentroidTree object + * @throws IllegalArgumentException if n <= 0 or edges is invalid + */ + public static CentroidTree buildFromEdges(int n, int[][] edges) { + if (n <= 0) { + throw new IllegalArgumentException("Number of nodes must be positive"); + } + if (edges == null) { + throw new IllegalArgumentException("Edges cannot be null"); + } + if (edges.length != n - 1) { + throw new IllegalArgumentException("Tree must have exactly n-1 edges"); + } + + List> adj = new ArrayList<>(); + for (int i = 0; i < n; i++) { + adj.add(new ArrayList<>()); + } + + for (int[] edge : edges) { + if (edge.length != 2) { + throw new IllegalArgumentException("Each edge must have exactly 2 nodes"); + } + int u = edge[0]; + int v = edge[1]; + + if (u < 0 || u >= n || v < 0 || v >= n) { + throw new IllegalArgumentException("Invalid node in edge: [" + u + ", " + v + "]"); + } + + adj.get(u).add(v); + adj.get(v).add(u); + } + + return new CentroidTree(adj); + } +} diff --git a/src/test/java/com/thealgorithms/datastructures/trees/CentroidDecompositionTest.java b/src/test/java/com/thealgorithms/datastructures/trees/CentroidDecompositionTest.java new file mode 100644 index 000000000000..43d732e54f34 --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/trees/CentroidDecompositionTest.java @@ -0,0 +1,236 @@ +package com.thealgorithms.datastructures.trees; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; + +/** + * Test cases for CentroidDecomposition + * + * @author lens161 + */ +class CentroidDecompositionTest { + + @Test + void testSingleNode() { + // Tree with just one node + int[][] edges = {}; + CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(1, edges); + + assertEquals(1, tree.size()); + assertEquals(0, tree.getRoot()); + assertEquals(-1, tree.getParent(0)); + } + + @Test + void testTwoNodes() { + // Simple tree: 0 - 1 + int[][] edges = {{0, 1}}; + CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(2, edges); + + assertEquals(2, tree.size()); + int root = tree.getRoot(); + assertTrue(root == 0 || root == 1, "Root should be either node 0 or 1"); + + // One node should be root, other should have the root as parent + int nonRoot = (root == 0) ? 1 : 0; + assertEquals(-1, tree.getParent(root)); + assertEquals(root, tree.getParent(nonRoot)); + } + + @Test + void testLinearTree() { + // Linear tree: 0 - 1 - 2 - 3 - 4 + int[][] edges = {{0, 1}, {1, 2}, {2, 3}, {3, 4}}; + CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(5, edges); + + assertEquals(5, tree.size()); + // For a linear tree of 5 nodes, the centroid should be the middle node (node 2) + assertEquals(2, tree.getRoot()); + assertEquals(-1, tree.getParent(2)); + } + + @Test + void testBalancedBinaryTree() { + // Balanced binary tree: + // 0 + // / \ + // 1 2 + // / \ + // 3 4 + int[][] edges = {{0, 1}, {0, 2}, {1, 3}, {1, 4}}; + CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(5, edges); + + assertEquals(5, tree.size()); + // Root should be 0 or 1 (both are valid centroids) + int root = tree.getRoot(); + assertTrue(root == 0 || root == 1); + assertEquals(-1, tree.getParent(root)); + + // All nodes should have a parent in centroid tree except root + for (int i = 0; i < 5; i++) { + if (i != root) { + assertTrue(tree.getParent(i) >= 0 && tree.getParent(i) < 5); + } + } + } + + @Test + void testStarTree() { + // Star tree: center node 0 connected to 1, 2, 3, 4 + int[][] edges = {{0, 1}, {0, 2}, {0, 3}, {0, 4}}; + CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(5, edges); + + assertEquals(5, tree.size()); + // Center node (0) should be the root + assertEquals(0, tree.getRoot()); + + // All other nodes should have 0 as parent + for (int i = 1; i < 5; i++) { + assertEquals(0, tree.getParent(i)); + } + } + + @Test + void testCompleteTree() { + // Complete binary tree of 7 nodes: + // 0 + // / \ + // 1 2 + // / \ / \ + // 3 4 5 6 + int[][] edges = {{0, 1}, {0, 2}, {1, 3}, {1, 4}, {2, 5}, {2, 6}}; + CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(7, edges); + + assertEquals(7, tree.size()); + assertEquals(0, tree.getRoot()); // Root should be the center + + // Verify all nodes are reachable in centroid tree + boolean[] visited = new boolean[7]; + visited[0] = true; + for (int i = 1; i < 7; i++) { + int parent = tree.getParent(i); + assertTrue(parent >= 0 && parent < 7); + assertTrue(visited[parent], "Parent should be processed before child"); + visited[i] = true; + } + } + + @Test + void testLargerTree() { + // Tree with 10 nodes + int[][] edges = {{0, 1}, {0, 2}, {1, 3}, {1, 4}, {2, 5}, {2, 6}, {3, 7}, {4, 8}, {5, 9}}; + CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(10, edges); + + assertEquals(10, tree.size()); + int root = tree.getRoot(); + assertTrue(root >= 0 && root < 10); + assertEquals(-1, tree.getParent(root)); + + // Verify centroid tree structure is valid + for (int i = 0; i < 10; i++) { + if (i != root) { + assertTrue(tree.getParent(i) >= -1 && tree.getParent(i) < 10); + } + } + } + + @Test + void testPathGraph() { + // Path graph with 8 nodes: 0-1-2-3-4-5-6-7 + int[][] edges = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 5}, {5, 6}, {6, 7}}; + CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(8, edges); + + assertEquals(8, tree.size()); + // For path of 8 nodes, centroid should be around middle + int root = tree.getRoot(); + assertTrue(root >= 2 && root <= 5, "Root should be near the middle of path"); + } + + @Test + void testInvalidEmptyTree() { + assertThrows(IllegalArgumentException.class, () -> { CentroidDecomposition.buildFromEdges(0, new int[][] {}); }); + } + + @Test + void testInvalidNegativeNodes() { + assertThrows(IllegalArgumentException.class, () -> { CentroidDecomposition.buildFromEdges(-1, new int[][] {}); }); + } + + @Test + void testInvalidNullEdges() { + assertThrows(IllegalArgumentException.class, () -> { CentroidDecomposition.buildFromEdges(5, null); }); + } + + @Test + void testInvalidEdgeCount() { + // Tree with n nodes must have n-1 edges + int[][] edges = {{0, 1}, {1, 2}}; // 2 edges for 5 nodes (should be 4) + assertThrows(IllegalArgumentException.class, () -> { CentroidDecomposition.buildFromEdges(5, edges); }); + } + + @Test + void testInvalidEdgeFormat() { + int[][] edges = {{0, 1, 2}}; // Edge with 3 elements instead of 2 + assertThrows(IllegalArgumentException.class, () -> { CentroidDecomposition.buildFromEdges(3, edges); }); + } + + @Test + void testInvalidNodeInEdge() { + int[][] edges = {{0, 5}}; // Node 5 doesn't exist in tree of size 3 + assertThrows(IllegalArgumentException.class, () -> { CentroidDecomposition.buildFromEdges(3, edges); }); + } + + @Test + void testInvalidNodeQuery() { + int[][] edges = {{0, 1}, {1, 2}}; + CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(3, edges); + + assertThrows(IllegalArgumentException.class, () -> { tree.getParent(-1); }); + + assertThrows(IllegalArgumentException.class, () -> { tree.getParent(5); }); + } + + @Test + void testToString() { + int[][] edges = {{0, 1}, {1, 2}}; + CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(3, edges); + + String result = tree.toString(); + assertNotNull(result); + assertTrue(result.contains("Centroid Tree")); + assertTrue(result.contains("Node")); + assertTrue(result.contains("ROOT")); + } + + @Test + void testAdjacencyListConstructor() { + List> adj = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + adj.add(new ArrayList<>()); + } + adj.get(0).add(1); + adj.get(1).add(0); + adj.get(1).add(2); + adj.get(2).add(1); + + CentroidDecomposition.CentroidTree tree = new CentroidDecomposition.CentroidTree(adj); + assertEquals(3, tree.size()); + assertEquals(1, tree.getRoot()); + } + + @Test + void testNullAdjacencyList() { + assertThrows(IllegalArgumentException.class, () -> { new CentroidDecomposition.CentroidTree(null); }); + } + + @Test + void testEmptyAdjacencyList() { + assertThrows(IllegalArgumentException.class, () -> { new CentroidDecomposition.CentroidTree(new ArrayList<>()); }); + } +} From f693c44b539508cd262374a6d8e9d7329301d6cc Mon Sep 17 00:00:00 2001 From: Deniz Altunkapan Date: Sat, 22 Nov 2025 18:26:16 +0100 Subject: [PATCH 51/74] fix: prevent duplicate auth header in GitHub Actions workflow (#7091) --- .github/workflows/update-directorymd.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/update-directorymd.yml b/.github/workflows/update-directorymd.yml index f6c91abe0e74..101d82427e38 100644 --- a/.github/workflows/update-directorymd.yml +++ b/.github/workflows/update-directorymd.yml @@ -1,4 +1,4 @@ -name: Generate Directory Markdown +name: Generate Directory Markdown on: push: @@ -15,6 +15,8 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v6 + with: + persist-credentials: false - name: Run Directory Tree Generator uses: DenizAltunkapan/directory-tree-generator@v2 From 1c6026ecc640b26d21bf5386872ef99de3d42c60 Mon Sep 17 00:00:00 2001 From: Eswar Venkata Ram Charan Seeram Date: Tue, 25 Nov 2025 01:46:16 +0530 Subject: [PATCH 52/74] fix: correct error message in surfaceAreaCylinder method (#7106) --- src/main/java/com/thealgorithms/maths/Area.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/maths/Area.java b/src/main/java/com/thealgorithms/maths/Area.java index a34ad6b01ab5..1eba6666dde3 100644 --- a/src/main/java/com/thealgorithms/maths/Area.java +++ b/src/main/java/com/thealgorithms/maths/Area.java @@ -96,7 +96,7 @@ public static double surfaceAreaCylinder(final double radius, final double heigh throw new IllegalArgumentException(POSITIVE_RADIUS); } if (height <= 0) { - throw new IllegalArgumentException(POSITIVE_RADIUS); + throw new IllegalArgumentException(POSITIVE_HEIGHT); } return 2 * (Math.PI * radius * radius + Math.PI * radius * height); } From 2c4bf3c7c88b2f3b7bfa6baeebb7b569e0530a5a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Nov 2025 16:36:37 +0100 Subject: [PATCH 53/74] chore(deps): bump com.github.spotbugs:spotbugs-maven-plugin from 4.9.8.1 to 4.9.8.2 (#7109) chore(deps): bump com.github.spotbugs:spotbugs-maven-plugin Bumps [com.github.spotbugs:spotbugs-maven-plugin](https://github.com/spotbugs/spotbugs-maven-plugin) from 4.9.8.1 to 4.9.8.2. - [Release notes](https://github.com/spotbugs/spotbugs-maven-plugin/releases) - [Commits](https://github.com/spotbugs/spotbugs-maven-plugin/compare/spotbugs-maven-plugin-4.9.8.1...spotbugs-maven-plugin-4.9.8.2) --- updated-dependencies: - dependency-name: com.github.spotbugs:spotbugs-maven-plugin dependency-version: 4.9.8.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 774db2ec4403..eb2aafc0fcc0 100644 --- a/pom.xml +++ b/pom.xml @@ -119,7 +119,7 @@ com.github.spotbugs spotbugs-maven-plugin - 4.9.8.1 + 4.9.8.2 spotbugs-exclude.xml true From a14e1e37669f0d8841e4a5bae07726da21e64736 Mon Sep 17 00:00:00 2001 From: prasanth-30011 Date: Wed, 26 Nov 2025 16:51:07 +0530 Subject: [PATCH 54/74] docs: improve javadoc for Combination class (#7126) Updated class documentation to reflect that the class finds combinations instead of permutations. --- src/main/java/com/thealgorithms/backtracking/Combination.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/backtracking/Combination.java b/src/main/java/com/thealgorithms/backtracking/Combination.java index ecaf7428f986..377d2c862d54 100644 --- a/src/main/java/com/thealgorithms/backtracking/Combination.java +++ b/src/main/java/com/thealgorithms/backtracking/Combination.java @@ -7,8 +7,7 @@ import java.util.TreeSet; /** - * Finds all permutations of given array - * @author Alan Piao (git-Alan Piao) + * Finds all combinations of a given array using backtracking algorithm * @author Alan Piao (git-Alan Piao) */ public final class Combination { private Combination() { From e841d73837c17d462e8bdfbb4d601e6744082981 Mon Sep 17 00:00:00 2001 From: Jayana Anjani Pavan Vardhan Naidu Date: Thu, 27 Nov 2025 16:55:52 +0530 Subject: [PATCH 55/74] Update Javadoc for perimeterIrregularPolygon method (#7141) Fixed incorrect @return description in perimeterIrregularPolygon method javadoc. Changed "trapezoid" to "irregular polygon" to accurately reflect what the method calculates. --- src/main/java/com/thealgorithms/maths/Perimeter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/maths/Perimeter.java b/src/main/java/com/thealgorithms/maths/Perimeter.java index f8aa1876d388..670851eb346b 100644 --- a/src/main/java/com/thealgorithms/maths/Perimeter.java +++ b/src/main/java/com/thealgorithms/maths/Perimeter.java @@ -27,7 +27,7 @@ public static float perimeterRegularPolygon(int n, float side) { * @param side2 for length of side 2 * @param side3 for length of side 3 * @param sides for length of remaining sides - * @return Perimeter of given trapezoid. + * @return Perimeter of given irregular polygon. */ public static float perimeterIrregularPolygon(float side1, float side2, float side3, float... sides) { float perimeter = side1 + side2 + side3; From d1ea3069203b5d2a132f2cf553424fbf4c2e3353 Mon Sep 17 00:00:00 2001 From: Gokul45-45 <2400032465@kluniversity.in> Date: Thu, 27 Nov 2025 16:59:48 +0530 Subject: [PATCH 56/74] feat: add Valid Parentheses algorithm using Stack (#7117) * feat: add Valid Parentheses algorithm using Stack * fix: add missing ValidParentheses.java implementation * fix: remove trailing spaces and add newline at EOF * fix: remove misplaced ValidParentheses.java from root --- .../stacks/ValidParentheses.java | 74 +++++++++++++++++++ .../stacks/ValidParenthesesTest.java | 32 ++++++++ 2 files changed, 106 insertions(+) create mode 100644 src/main/java/com/thealgorithms/stacks/ValidParentheses.java create mode 100644 src/test/java/com/thealgorithms/stacks/ValidParenthesesTest.java diff --git a/src/main/java/com/thealgorithms/stacks/ValidParentheses.java b/src/main/java/com/thealgorithms/stacks/ValidParentheses.java new file mode 100644 index 000000000000..2cc616a38826 --- /dev/null +++ b/src/main/java/com/thealgorithms/stacks/ValidParentheses.java @@ -0,0 +1,74 @@ +package com.thealgorithms.stacks; + +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; + +/** + * Valid Parentheses Problem + * + * Given a string containing just the characters '(', ')', '{', '}', '[' and ']', + * determine if the input string is valid. + * + * An input string is valid if: + * 1. Open brackets must be closed by the same type of brackets. + * 2. Open brackets must be closed in the correct order. + * 3. Every close bracket has a corresponding open bracket of the same type. + * + * Examples: + * Input: "()" + * Output: true + * + * Input: "()[]{}" + * Output: true + * + * Input: "(]" + * Output: false + * + * Input: "([)]" + * Output: false + * + * @author Gokul45-45 + */ +public final class ValidParentheses { + private ValidParentheses() { + } + + /** + * Checks if the given string has valid parentheses + * + * @param s the input string containing parentheses + * @return true if valid, false otherwise + */ + public static boolean isValid(String s) { + if (s == null || s.length() % 2 != 0) { + return false; + } + + Map parenthesesMap = new HashMap<>(); + parenthesesMap.put('(', ')'); + parenthesesMap.put('{', '}'); + parenthesesMap.put('[', ']'); + + Stack stack = new Stack<>(); + + for (char c : s.toCharArray()) { + if (parenthesesMap.containsKey(c)) { + // Opening bracket - push to stack + stack.push(c); + } else { + // Closing bracket - check if it matches + if (stack.isEmpty()) { + return false; + } + char openBracket = stack.pop(); + if (parenthesesMap.get(openBracket) != c) { + return false; + } + } + } + + // Stack should be empty if all brackets are matched + return stack.isEmpty(); + } +} diff --git a/src/test/java/com/thealgorithms/stacks/ValidParenthesesTest.java b/src/test/java/com/thealgorithms/stacks/ValidParenthesesTest.java new file mode 100644 index 000000000000..39014780caa9 --- /dev/null +++ b/src/test/java/com/thealgorithms/stacks/ValidParenthesesTest.java @@ -0,0 +1,32 @@ +package com.thealgorithms.stacks; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class ValidParenthesesTest { + + @Test + void testValidParentheses() { + assertTrue(ValidParentheses.isValid("()")); + assertTrue(ValidParentheses.isValid("()[]{}")); + assertTrue(ValidParentheses.isValid("{[]}")); + assertTrue(ValidParentheses.isValid("")); + } + + @Test + void testInvalidParentheses() { + assertFalse(ValidParentheses.isValid("(]")); + assertFalse(ValidParentheses.isValid("([)]")); + assertFalse(ValidParentheses.isValid("{{{")); + assertFalse(ValidParentheses.isValid("}")); + assertFalse(ValidParentheses.isValid("(")); + } + + @Test + void testNullAndOddLength() { + assertFalse(ValidParentheses.isValid(null)); + assertFalse(ValidParentheses.isValid("(()")); + } +} From f352f8111ba3fdcc87674263c0907f9452f5b0b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Nov 2025 09:26:07 +0100 Subject: [PATCH 57/74] chore(deps): bump com.mebigfatguy.fb-contrib:fb-contrib from 7.7.0 to 7.7.1 (#7144) chore(deps): bump com.mebigfatguy.fb-contrib:fb-contrib Bumps [com.mebigfatguy.fb-contrib:fb-contrib](https://github.com/mebigfatguy/fb-contrib) from 7.7.0 to 7.7.1. - [Commits](https://github.com/mebigfatguy/fb-contrib/commits) --- updated-dependencies: - dependency-name: com.mebigfatguy.fb-contrib:fb-contrib dependency-version: 7.7.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index eb2aafc0fcc0..6b918cdad5bb 100644 --- a/pom.xml +++ b/pom.xml @@ -127,7 +127,7 @@ com.mebigfatguy.fb-contrib fb-contrib - 7.7.0 + 7.7.1 com.h3xstream.findsecbugs From 4c5525a2e0a9b18b879d774398d1a0f5ca29c509 Mon Sep 17 00:00:00 2001 From: Sameer Prajapati Date: Fri, 28 Nov 2025 14:17:53 +0530 Subject: [PATCH 58/74] =?UTF-8?q?feat:=20Added=20Gomory=E2=80=93Hu=20Tree?= =?UTF-8?q?=20(all-pairs=20min-cuts=20via=20n1=20max-flows)=20(#6818)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Gomory–Hu Tree (all-pairs min-cuts via n1 max-flows) * Stabilize Monte Carlo integration with antithetic variates to reduce variance * Fix Checkstyle in GomoryHuTreeTest: remove inner assignments, add braces, split declarations * SpotBugs: use RandomGenerator interface in test helper --------- Co-authored-by: Deniz Altunkapan --- DIRECTORY.md | 1 + .../com/thealgorithms/graph/GomoryHuTree.java | 144 ++++++++++++++++++ .../randomized/MonteCarloIntegration.java | 16 +- .../thealgorithms/graph/GomoryHuTreeTest.java | 132 ++++++++++++++++ 4 files changed, 289 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/thealgorithms/graph/GomoryHuTree.java create mode 100644 src/test/java/com/thealgorithms/graph/GomoryHuTreeTest.java diff --git a/DIRECTORY.md b/DIRECTORY.md index 042efa72addc..b8db96ffa993 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -385,6 +385,7 @@ - 📄 [Dinic](src/main/java/com/thealgorithms/graph/Dinic.java) - 📄 [Edmonds](src/main/java/com/thealgorithms/graph/Edmonds.java) - 📄 [EdmondsKarp](src/main/java/com/thealgorithms/graph/EdmondsKarp.java) + - 📄 [GomoryHuTree](src/main/java/com/thealgorithms/graph/GomoryHuTree.java) - 📄 [HierholzerAlgorithm](src/main/java/com/thealgorithms/graph/HierholzerAlgorithm.java) - 📄 [HierholzerEulerianPath](src/main/java/com/thealgorithms/graph/HierholzerEulerianPath.java) - 📄 [HopcroftKarp](src/main/java/com/thealgorithms/graph/HopcroftKarp.java) diff --git a/src/main/java/com/thealgorithms/graph/GomoryHuTree.java b/src/main/java/com/thealgorithms/graph/GomoryHuTree.java new file mode 100644 index 000000000000..f8c110f25571 --- /dev/null +++ b/src/main/java/com/thealgorithms/graph/GomoryHuTree.java @@ -0,0 +1,144 @@ +package com.thealgorithms.graph; + +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Queue; + +/** + * Gomory–Hu tree construction for undirected graphs via n−1 max-flow computations. + * + *

API: {@code buildTree(int[][])} returns {@code {parent, weight}} arrays for the tree. + * + * @see Wikipedia: Gomory–Hu tree + */ + +public final class GomoryHuTree { + private GomoryHuTree() { + } + + public static int[][] buildTree(int[][] cap) { + validateCapacityMatrix(cap); + final int n = cap.length; + if (n == 1) { + return new int[][] {new int[] {-1}, new int[] {0}}; + } + + int[] parent = new int[n]; + int[] weight = new int[n]; + Arrays.fill(parent, 0); + parent[0] = -1; + weight[0] = 0; + + for (int s = 1; s < n; s++) { + int t = parent[s]; + MaxFlowResult res = edmondsKarpWithMinCut(cap, s, t); + int f = res.flow; + weight[s] = f; + + for (int v = 0; v < n; v++) { + if (v != s && parent[v] == t && res.reachable[v]) { + parent[v] = s; + } + } + + if (t != 0 && res.reachable[parent[t]]) { + parent[s] = parent[t]; + parent[t] = s; + weight[s] = weight[t]; + weight[t] = f; + } + } + return new int[][] {parent, weight}; + } + + private static void validateCapacityMatrix(int[][] cap) { + if (cap == null || cap.length == 0) { + throw new IllegalArgumentException("Capacity matrix must not be null or empty"); + } + final int n = cap.length; + for (int i = 0; i < n; i++) { + if (cap[i] == null || cap[i].length != n) { + throw new IllegalArgumentException("Capacity matrix must be square"); + } + for (int j = 0; j < n; j++) { + if (cap[i][j] < 0) { + throw new IllegalArgumentException("Capacities must be non-negative"); + } + } + } + } + + private static final class MaxFlowResult { + final int flow; + final boolean[] reachable; + MaxFlowResult(int flow, boolean[] reachable) { + this.flow = flow; + this.reachable = reachable; + } + } + + private static MaxFlowResult edmondsKarpWithMinCut(int[][] capacity, int source, int sink) { + final int n = capacity.length; + int[][] residual = new int[n][n]; + for (int i = 0; i < n; i++) { + residual[i] = Arrays.copyOf(capacity[i], n); + } + + int[] parent = new int[n]; + int maxFlow = 0; + + while (bfs(residual, source, sink, parent)) { + int pathFlow = Integer.MAX_VALUE; + for (int v = sink; v != source; v = parent[v]) { + int u = parent[v]; + pathFlow = Math.min(pathFlow, residual[u][v]); + } + for (int v = sink; v != source; v = parent[v]) { + int u = parent[v]; + residual[u][v] -= pathFlow; + residual[v][u] += pathFlow; + } + maxFlow += pathFlow; + } + + boolean[] reachable = new boolean[n]; + markReachable(residual, source, reachable); + return new MaxFlowResult(maxFlow, reachable); + } + + private static boolean bfs(int[][] residual, int source, int sink, int[] parent) { + Arrays.fill(parent, -1); + parent[source] = source; + Queue q = new ArrayDeque<>(); + q.add(source); + while (!q.isEmpty()) { + int u = q.poll(); + for (int v = 0; v < residual.length; v++) { + if (residual[u][v] > 0 && parent[v] == -1) { + parent[v] = u; + if (v == sink) { + return true; + } + q.add(v); + } + } + } + return false; + } + + private static void markReachable(int[][] residual, int source, boolean[] vis) { + Arrays.fill(vis, false); + Queue q = new ArrayDeque<>(); + vis[source] = true; + q.add(source); + while (!q.isEmpty()) { + int u = q.poll(); + for (int v = 0; v < residual.length; v++) { + if (!vis[v] && residual[u][v] > 0) { + vis[v] = true; + q.add(v); + } + } + } + } +} diff --git a/src/main/java/com/thealgorithms/randomized/MonteCarloIntegration.java b/src/main/java/com/thealgorithms/randomized/MonteCarloIntegration.java index 05d7abbbcd6c..06101295e880 100644 --- a/src/main/java/com/thealgorithms/randomized/MonteCarloIntegration.java +++ b/src/main/java/com/thealgorithms/randomized/MonteCarloIntegration.java @@ -64,13 +64,21 @@ private static double doApproximate(Function fx, double a, doubl if (!validate(fx, a, b, n)) { throw new IllegalArgumentException("Invalid input parameters"); } - double totalArea = 0.0; + double total = 0.0; double interval = b - a; - for (int i = 0; i < n; i++) { + int pairs = n / 2; + for (int i = 0; i < pairs; i++) { + double u = generator.nextDouble(); + double x1 = a + u * interval; + double x2 = a + (1.0 - u) * interval; + total += fx.apply(x1); + total += fx.apply(x2); + } + if ((n & 1) == 1) { double x = a + generator.nextDouble() * interval; - totalArea += fx.apply(x); + total += fx.apply(x); } - return interval * totalArea / n; + return interval * total / n; } private static boolean validate(Function fx, double a, double b, int n) { diff --git a/src/test/java/com/thealgorithms/graph/GomoryHuTreeTest.java b/src/test/java/com/thealgorithms/graph/GomoryHuTreeTest.java new file mode 100644 index 000000000000..241f23c0fa1d --- /dev/null +++ b/src/test/java/com/thealgorithms/graph/GomoryHuTreeTest.java @@ -0,0 +1,132 @@ +package com.thealgorithms.graph; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Queue; +import java.util.Random; +import java.util.random.RandomGenerator; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class GomoryHuTreeTest { + + @Test + @DisplayName("Single node graph") + void singleNode() { + int[][] cap = {{0}}; + int[][] res = GomoryHuTree.buildTree(cap); + int[] parent = res[0]; + int[] weight = res[1]; + assertEquals(-1, parent[0]); + assertEquals(0, weight[0]); + } + + @Test + @DisplayName("Triangle undirected graph with known min-cuts") + void triangleGraph() { + // 0-1:3, 1-2:2, 0-2:4 + int[][] cap = new int[3][3]; + cap[0][1] = 3; + cap[1][0] = 3; + cap[1][2] = 2; + cap[2][1] = 2; + cap[0][2] = 4; + cap[2][0] = 4; + + int[][] tree = GomoryHuTree.buildTree(cap); + // validate all pairs via path-min-edge equals maxflow + validateAllPairs(cap, tree); + } + + @Test + @DisplayName("Random small undirected graphs compare to EdmondsKarp") + void randomSmallGraphs() { + Random rng = new Random(42); + for (int n = 2; n <= 6; n++) { + for (int iter = 0; iter < 10; iter++) { + int[][] cap = randSymmetricMatrix(n, 0, 5, rng); + int[][] tree = GomoryHuTree.buildTree(cap); + validateAllPairs(cap, tree); + } + } + } + + private static int[][] randSymmetricMatrix(int n, int lo, int hi, RandomGenerator rng) { + int[][] a = new int[n][n]; + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + int w = rng.nextInt(hi - lo + 1) + lo; + a[i][j] = w; + a[j][i] = w; + } + } + // zero diagonal + for (int i = 0; i < n; i++) { + a[i][i] = 0; + } + return a; + } + + private static void validateAllPairs(int[][] cap, int[][] tree) { + int n = cap.length; + int[] parent = tree[0]; + int[] weight = tree[1]; + + // build adjacency list of tree without generic array creation + List> g = new ArrayList<>(); + for (int i = 0; i < n; i++) { + g.add(new ArrayList<>()); + } + for (int v = 1; v < n; v++) { + int u = parent[v]; + int w = weight[v]; + g.get(u).add(new int[] {v, w}); + g.get(v).add(new int[] {u, w}); + } + + for (int s = 0; s < n; s++) { + for (int t = s + 1; t < n; t++) { + int treeVal = minEdgeOnPath(g, s, t); + int flowVal = EdmondsKarp.maxFlow(cap, s, t); + assertEquals(flowVal, treeVal, "pair (" + s + "," + t + ")"); + } + } + } + + private static int minEdgeOnPath(List> g, int s, int t) { + // BFS to record parent and edge weight along the path, since it's a tree, unique path exists + int n = g.size(); + int[] parent = new int[n]; + int[] edgeW = new int[n]; + Arrays.fill(parent, -1); + Queue q = new ArrayDeque<>(); + q.add(s); + parent[s] = s; + while (!q.isEmpty()) { + int u = q.poll(); + if (u == t) { + break; + } + for (int[] e : g.get(u)) { + int v = e[0]; + int w = e[1]; + if (parent[v] == -1) { + parent[v] = u; + edgeW[v] = w; + q.add(v); + } + } + } + int cur = t; + int ans = Integer.MAX_VALUE; + while (cur != s) { + ans = Math.min(ans, edgeW[cur]); + cur = parent[cur]; + } + return ans == Integer.MAX_VALUE ? 0 : ans; + } +} From a9ba87c4b6efc77f8444fdc94de26af3c6f67df2 Mon Sep 17 00:00:00 2001 From: Taranjeet Singh Kalsi Date: Fri, 28 Nov 2025 14:21:28 +0530 Subject: [PATCH 59/74] Added program to check Abundant number (#6961) added program for abundant number --- .../thealgorithms/maths/AbundantNumber.java | 58 +++++++++++++++++++ .../maths/AbundantNumberTest.java | 31 ++++++++++ 2 files changed, 89 insertions(+) create mode 100644 src/main/java/com/thealgorithms/maths/AbundantNumber.java create mode 100644 src/test/java/com/thealgorithms/maths/AbundantNumberTest.java diff --git a/src/main/java/com/thealgorithms/maths/AbundantNumber.java b/src/main/java/com/thealgorithms/maths/AbundantNumber.java new file mode 100644 index 000000000000..804ac4d71477 --- /dev/null +++ b/src/main/java/com/thealgorithms/maths/AbundantNumber.java @@ -0,0 +1,58 @@ +package com.thealgorithms.maths; + +/** + * In number theory, an abundant number or excessive number is a positive integer for which + * the sum of its proper divisors is greater than the number. + * Equivalently, it is a number for which the sum of proper divisors (or aliquot sum) is greater than n. + * + * The integer 12 is the first abundant number. Its proper divisors are 1, 2, 3, 4 and 6 for a total of 16. + * + * Wiki: https://en.wikipedia.org/wiki/Abundant_number + */ +public final class AbundantNumber { + + private AbundantNumber() { + } + + // Function to calculate sum of all divisors including n + private static int sumOfDivisors(int n) { + int sum = 1 + n; // 1 and n are always divisors + for (int i = 2; i <= n / 2; i++) { + if (n % i == 0) { + sum += i; // adding divisor to sum + } + } + return sum; + } + + // Common validation method + private static void validatePositiveNumber(int number) { + if (number <= 0) { + throw new IllegalArgumentException("Number must be positive."); + } + } + + /** + * Check if {@code number} is an Abundant number or not by checking sum of divisors > 2n + * + * @param number the number + * @return {@code true} if {@code number} is an Abundant number, otherwise false + */ + public static boolean isAbundant(int number) { + validatePositiveNumber(number); + + return sumOfDivisors(number) > 2 * number; + } + + /** + * Check if {@code number} is an Abundant number or not by checking Aliquot Sum > n + * + * @param number the number + * @return {@code true} if {@code number} is a Abundant number, otherwise false + */ + public static boolean isAbundantNumber(int number) { + validatePositiveNumber(number); + + return AliquotSum.getAliquotSum(number) > number; + } +} diff --git a/src/test/java/com/thealgorithms/maths/AbundantNumberTest.java b/src/test/java/com/thealgorithms/maths/AbundantNumberTest.java new file mode 100644 index 000000000000..5b35345afd02 --- /dev/null +++ b/src/test/java/com/thealgorithms/maths/AbundantNumberTest.java @@ -0,0 +1,31 @@ +package com.thealgorithms.maths; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +class AbundantNumberTest { + @ParameterizedTest + @CsvSource({"12", "66", "222", "444", "888", "2424"}) + void abundantNumbersTest(int n) { + assertTrue(AbundantNumber.isAbundant(n)); + assertTrue(AbundantNumber.isAbundantNumber(n)); + } + + @ParameterizedTest + @CsvSource({"1", "2", "6", "111", "333", "2222"}) + void nonAbundantNumbersTest(int n) { + assertFalse(AbundantNumber.isAbundant(n)); + assertFalse(AbundantNumber.isAbundantNumber(n)); + } + + @ParameterizedTest + @CsvSource({"0", "-1"}) + void throwsNegativeNumbersNotAllowed(int n) { + assertThrows(IllegalArgumentException.class, () -> AbundantNumber.isAbundant(n)); + assertThrows(IllegalArgumentException.class, () -> AbundantNumber.isAbundantNumber(n)); + } +} From ac6fef19dc1a689f8e16a8a7361d1868c2c69e83 Mon Sep 17 00:00:00 2001 From: Taranjeet Singh Kalsi Date: Mon, 1 Dec 2025 04:07:41 +0530 Subject: [PATCH 60/74] Added program to check either number is Evil or Odious (#6958) added program for evil number --- .../com/thealgorithms/maths/EvilNumber.java | 39 +++++++++++++++++++ .../thealgorithms/maths/EvilNumberTest.java | 28 +++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 src/main/java/com/thealgorithms/maths/EvilNumber.java create mode 100644 src/test/java/com/thealgorithms/maths/EvilNumberTest.java diff --git a/src/main/java/com/thealgorithms/maths/EvilNumber.java b/src/main/java/com/thealgorithms/maths/EvilNumber.java new file mode 100644 index 000000000000..419133702fd4 --- /dev/null +++ b/src/main/java/com/thealgorithms/maths/EvilNumber.java @@ -0,0 +1,39 @@ +package com.thealgorithms.maths; + +/** + * In number theory, an evil number is a non-negative integer that has an even number of 1s in its binary expansion. + * Non-negative integers that are not evil are called odious numbers. + * + * Evil Number Wiki: https://en.wikipedia.org/wiki/Evil_number + * Odious Number Wiki: https://en.wikipedia.org/wiki/Odious_number + */ +public final class EvilNumber { + + private EvilNumber() { + } + + // Function to count number of one bits in a number using bitwise operators + private static int countOneBits(int number) { + int oneBitCounter = 0; + while (number > 0) { + oneBitCounter += number & 1; // increment count if last bit is 1 + number >>= 1; // right shift to next bit + } + return oneBitCounter; + } + + /** + * Check either {@code number} is an Evil number or Odious number + * + * @param number the number + * @return {@code true} if {@code number} is an Evil number, otherwise false (in case of of Odious number) + */ + public static boolean isEvilNumber(int number) { + if (number < 0) { + throw new IllegalArgumentException("Negative numbers are not allowed."); + } + + int noOfOneBits = countOneBits(number); + return noOfOneBits % 2 == 0; + } +} diff --git a/src/test/java/com/thealgorithms/maths/EvilNumberTest.java b/src/test/java/com/thealgorithms/maths/EvilNumberTest.java new file mode 100644 index 000000000000..e59171fad25f --- /dev/null +++ b/src/test/java/com/thealgorithms/maths/EvilNumberTest.java @@ -0,0 +1,28 @@ +package com.thealgorithms.maths; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +class EvilNumberTest { + @ParameterizedTest + @CsvSource({"0", "3", "10", "129", "222", "500", "777", "1198"}) + void evilNumbersTest(int n) { + assertTrue(EvilNumber.isEvilNumber(n)); + } + + @ParameterizedTest + @CsvSource({"1", "7", "100", "333", "555", "1199"}) + void odiousNumbersTest(int n) { + assertFalse(EvilNumber.isEvilNumber(n)); + } + + @ParameterizedTest + @CsvSource({"-1"}) + void throwsNegativeNumbersNotAllowed(int n) { + assertThrows(IllegalArgumentException.class, () -> EvilNumber.isEvilNumber(n)); + } +} From 14c0b0844e747e3c4a9b84e8a63b6db3f6f0294d Mon Sep 17 00:00:00 2001 From: Shewale Gopal Sanjay Date: Tue, 2 Dec 2025 01:43:14 +0530 Subject: [PATCH 61/74] Added threaded binary tree (#6995) * Add One-Time Pad Cipher implementation in Java * Add One-Time Pad Cipher implementation (fixed) * Add ThreadedBinaryTree with in-order traversal and tests * feat: add threaded binary tree implementation and tests * fix: remove redundant null check for SpotBugs compliance --- .../trees/ThreadedBinaryTree.java | 145 ++++++++++++++++++ .../trees/ThreadedBinaryTreeTest.java | 50 ++++++ 2 files changed, 195 insertions(+) create mode 100644 src/main/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTree.java create mode 100644 src/test/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTreeTest.java diff --git a/src/main/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTree.java b/src/main/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTree.java new file mode 100644 index 000000000000..fd8876cecb70 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTree.java @@ -0,0 +1,145 @@ +/* + * TheAlgorithms (https://github.com/TheAlgorithms/Java) + * Author: Shewale41 + * This file is licensed under the MIT License. + */ + +package com.thealgorithms.datastructures.trees; + +import java.util.ArrayList; +import java.util.List; + +/** + * Threaded binary tree implementation that supports insertion and + * in-order traversal without recursion or stack by using threads. + * + *

In this implementation, a node's null left/right pointers are used + * to point to the in-order predecessor/successor respectively. Two flags + * indicate whether left/right pointers are real children or threads. + * + * @see Wikipedia: + * Threaded binary tree + */ +public final class ThreadedBinaryTree { + + private Node root; + + private static final class Node { + int value; + Node left; + Node right; + boolean leftIsThread; + boolean rightIsThread; + + Node(int value) { + this.value = value; + this.left = null; + this.right = null; + this.leftIsThread = false; + this.rightIsThread = false; + } + } + + public ThreadedBinaryTree() { + this.root = null; + } + + /** + * Inserts a value into the threaded binary tree. Duplicate values are inserted + * to the right subtree (consistent deterministic rule). + * + * @param value the integer value to insert + */ + public void insert(int value) { + Node newNode = new Node(value); + if (root == null) { + root = newNode; + return; + } + + Node current = root; + Node parent = null; + + while (true) { + parent = current; + if (value < current.value) { + if (!current.leftIsThread && current.left != null) { + current = current.left; + } else { + break; + } + } else { // value >= current.value + if (!current.rightIsThread && current.right != null) { + current = current.right; + } else { + break; + } + } + } + + if (value < parent.value) { + // attach newNode as left child + newNode.left = parent.left; + newNode.leftIsThread = parent.leftIsThread; + newNode.right = parent; + newNode.rightIsThread = true; + + parent.left = newNode; + parent.leftIsThread = false; + } else { + // attach newNode as right child + newNode.right = parent.right; + newNode.rightIsThread = parent.rightIsThread; + newNode.left = parent; + newNode.leftIsThread = true; + + parent.right = newNode; + parent.rightIsThread = false; + } + } + + /** + * Returns the in-order traversal of the tree as a list of integers. + * Traversal is done without recursion or an explicit stack by following threads. + * + * @return list containing the in-order sequence of node values + */ + public List inorderTraversal() { + List result = new ArrayList<>(); + Node current = root; + if (current == null) { + return result; + } + + // Move to the leftmost node + while (current.left != null && !current.leftIsThread) { + current = current.left; + } + + while (current != null) { + result.add(current.value); + + // If right pointer is a thread, follow it + if (current.rightIsThread) { + current = current.right; + } else { + // Move to leftmost node in right subtree + current = current.right; + while (current != null && !current.leftIsThread && current.left != null) { + current = current.left; + } + } + } + + return result; + } + + /** + * Helper: checks whether the tree is empty. + * + * @return true if tree has no nodes + */ + public boolean isEmpty() { + return root == null; + } +} diff --git a/src/test/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTreeTest.java b/src/test/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTreeTest.java new file mode 100644 index 000000000000..c5973168438e --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTreeTest.java @@ -0,0 +1,50 @@ +/* + * TheAlgorithms (https://github.com/TheAlgorithms/Java) + * Author: Shewale41 + * This file is licensed under the MIT License. + */ + +package com.thealgorithms.datastructures.trees; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; +import org.junit.jupiter.api.Test; + +/** + * Basic tests for ThreadedBinaryTree inorder traversal. + */ +public class ThreadedBinaryTreeTest { + + @Test + public void testInorderTraversalSimple() { + ThreadedBinaryTree tree = new ThreadedBinaryTree(); + tree.insert(50); + tree.insert(30); + tree.insert(70); + tree.insert(20); + tree.insert(40); + tree.insert(60); + tree.insert(80); + + List expected = List.of(20, 30, 40, 50, 60, 70, 80); + List actual = tree.inorderTraversal(); + + assertEquals(expected, actual); + } + + @Test + public void testInorderWithDuplicates() { + ThreadedBinaryTree tree = new ThreadedBinaryTree(); + tree.insert(5); + tree.insert(3); + tree.insert(7); + tree.insert(7); // duplicate + tree.insert(2); + + List expected = List.of(2, 3, 5, 7, 7); + List actual = tree.inorderTraversal(); + + assertEquals(expected, actual); + } +} From 8d2cdb27db3b0979d28bbb2a723fa2e235a736b2 Mon Sep 17 00:00:00 2001 From: duvvuvenkataramana Date: Tue, 2 Dec 2025 01:47:32 +0530 Subject: [PATCH 62/74] feat: implement One-Time Pad cipher (#6941) (#7096) * feat: implement One-Time Pad cipher (#6941) * style: format OneTimePadCipher with clang-format --- .../ciphers/OneTimePadCipher.java | 89 +++++++++++++++++++ .../ciphers/OneTimePadCipherTest.java | 49 ++++++++++ 2 files changed, 138 insertions(+) create mode 100644 src/main/java/com/thealgorithms/ciphers/OneTimePadCipher.java create mode 100644 src/test/java/com/thealgorithms/ciphers/OneTimePadCipherTest.java diff --git a/src/main/java/com/thealgorithms/ciphers/OneTimePadCipher.java b/src/main/java/com/thealgorithms/ciphers/OneTimePadCipher.java new file mode 100644 index 000000000000..7733f5cb46f2 --- /dev/null +++ b/src/main/java/com/thealgorithms/ciphers/OneTimePadCipher.java @@ -0,0 +1,89 @@ +package com.thealgorithms.ciphers; + +import java.security.SecureRandom; +import java.util.Objects; + +/** + * One-Time Pad (OTP) cipher implementation. + * + *

The One-Time Pad is information-theoretically secure if: + *

    + *
  • The key is truly random.
  • + *
  • The key length is at least as long as the plaintext.
  • + *
  • The key is used only once and kept secret.
  • + *
+ * + *

This implementation is for educational purposes only and should not be + * used in production systems. + */ +public final class OneTimePadCipher { + + private static final SecureRandom RANDOM = new SecureRandom(); + + private OneTimePadCipher() { + // utility class + } + + /** + * Generates a random key of the given length in bytes. + * + * @param length the length of the key in bytes, must be non-negative + * @return a new random key + * @throws IllegalArgumentException if length is negative + */ + public static byte[] generateKey(int length) { + if (length < 0) { + throw new IllegalArgumentException("length must be non-negative"); + } + byte[] key = new byte[length]; + RANDOM.nextBytes(key); + return key; + } + + /** + * Encrypts the given plaintext bytes using the provided key. + *

The key length must be exactly the same as the plaintext length. + * + * @param plaintext the plaintext bytes, must not be {@code null} + * @param key the one-time pad key bytes, must not be {@code null} + * @return the ciphertext bytes + * @throws IllegalArgumentException if the key length does not match plaintext length + * @throws NullPointerException if plaintext or key is {@code null} + */ + public static byte[] encrypt(byte[] plaintext, byte[] key) { + validateInputs(plaintext, key); + return xor(plaintext, key); + } + + /** + * Decrypts the given ciphertext bytes using the provided key. + *

For a One-Time Pad, decryption is identical to encryption: + * {@code plaintext = ciphertext XOR key}. + * + * @param ciphertext the ciphertext bytes, must not be {@code null} + * @param key the one-time pad key bytes, must not be {@code null} + * @return the decrypted plaintext bytes + * @throws IllegalArgumentException if the key length does not match ciphertext length + * @throws NullPointerException if ciphertext or key is {@code null} + */ + public static byte[] decrypt(byte[] ciphertext, byte[] key) { + validateInputs(ciphertext, key); + return xor(ciphertext, key); + } + + private static void validateInputs(byte[] input, byte[] key) { + Objects.requireNonNull(input, "input must not be null"); + Objects.requireNonNull(key, "key must not be null"); + if (input.length != key.length) { + throw new IllegalArgumentException("Key length must match input length"); + } + } + + private static byte[] xor(byte[] data, byte[] key) { + byte[] result = new byte[data.length]; + for (int i = 0; i < data.length; i++) { + result[i] = (byte) (data[i] ^ key[i]); + } + return result; + } +} diff --git a/src/test/java/com/thealgorithms/ciphers/OneTimePadCipherTest.java b/src/test/java/com/thealgorithms/ciphers/OneTimePadCipherTest.java new file mode 100644 index 000000000000..837c56c603d4 --- /dev/null +++ b/src/test/java/com/thealgorithms/ciphers/OneTimePadCipherTest.java @@ -0,0 +1,49 @@ +package com.thealgorithms.ciphers; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Test; + +class OneTimePadCipherTest { + + @Test + void encryptAndDecryptWithRandomKeyRestoresPlaintext() { + String plaintext = "The quick brown fox jumps over the lazy dog."; + byte[] plaintextBytes = plaintext.getBytes(StandardCharsets.UTF_8); + + byte[] key = OneTimePadCipher.generateKey(plaintextBytes.length); + + byte[] ciphertext = OneTimePadCipher.encrypt(plaintextBytes, key); + byte[] decrypted = OneTimePadCipher.decrypt(ciphertext, key); + + assertArrayEquals(plaintextBytes, decrypted); + assertEquals(plaintext, new String(decrypted, StandardCharsets.UTF_8)); + } + + @Test + void generateKeyWithNegativeLengthThrowsException() { + assertThrows(IllegalArgumentException.class, () -> OneTimePadCipher.generateKey(-1)); + } + + @Test + void encryptWithMismatchedKeyLengthThrowsException() { + byte[] data = "hello".getBytes(StandardCharsets.UTF_8); + byte[] shortKey = OneTimePadCipher.generateKey(2); + + assertThrows(IllegalArgumentException.class, () -> OneTimePadCipher.encrypt(data, shortKey)); + } + + @Test + void decryptWithMismatchedKeyLengthThrowsException() { + byte[] data = "hello".getBytes(StandardCharsets.UTF_8); + byte[] key = OneTimePadCipher.generateKey(data.length); + byte[] ciphertext = OneTimePadCipher.encrypt(data, key); + + byte[] wrongSizedKey = OneTimePadCipher.generateKey(data.length + 1); + + assertThrows(IllegalArgumentException.class, () -> OneTimePadCipher.decrypt(ciphertext, wrongSizedKey)); + } +} From 927fe1f87cdfe2ea57051812427e78c9cf6f4775 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Dec 2025 09:54:59 +0100 Subject: [PATCH 63/74] chore(deps): bump com.puppycrawl.tools:checkstyle from 12.1.2 to 12.2.0 (#7147) Bumps [com.puppycrawl.tools:checkstyle](https://github.com/checkstyle/checkstyle) from 12.1.2 to 12.2.0. - [Release notes](https://github.com/checkstyle/checkstyle/releases) - [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-12.1.2...checkstyle-12.2.0) --- updated-dependencies: - dependency-name: com.puppycrawl.tools:checkstyle dependency-version: 12.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6b918cdad5bb..dc7d211b2742 100644 --- a/pom.xml +++ b/pom.xml @@ -112,7 +112,7 @@ com.puppycrawl.tools checkstyle - 12.1.2 + 12.2.0 From bd7f269aa992e87359d82b3d3d289b4fefde5eea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Dec 2025 08:58:42 +0000 Subject: [PATCH 64/74] chore(deps): bump gitpod/workspace-java-21 from 2025-10-06-13-14-25 to 2025-11-14-10-05-32 (#7148) chore(deps): bump gitpod/workspace-java-21 Bumps gitpod/workspace-java-21 from 2025-10-06-13-14-25 to 2025-11-14-10-05-32. --- updated-dependencies: - dependency-name: gitpod/workspace-java-21 dependency-version: 2025-11-14-10-05-32 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .gitpod.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitpod.dockerfile b/.gitpod.dockerfile index 4195f928d1bc..a8951da7de26 100644 --- a/.gitpod.dockerfile +++ b/.gitpod.dockerfile @@ -1,4 +1,4 @@ -FROM gitpod/workspace-java-21:2025-10-06-13-14-25 +FROM gitpod/workspace-java-21:2025-11-14-10-05-32 ENV LLVM_SCRIPT="tmp_llvm.sh" From 246162e5bdc6b9f4eb4cf8287e31eb44c36301da Mon Sep 17 00:00:00 2001 From: espinosadev <163946778+espinosa-dev@users.noreply.github.com> Date: Fri, 5 Dec 2025 16:45:25 +0100 Subject: [PATCH 65/74] Fixed redundant boolean logic (#7151) --- .../java/com/thealgorithms/strings/Upper.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/thealgorithms/strings/Upper.java b/src/main/java/com/thealgorithms/strings/Upper.java index 5e248cb6ee39..85db7d41e1aa 100644 --- a/src/main/java/com/thealgorithms/strings/Upper.java +++ b/src/main/java/com/thealgorithms/strings/Upper.java @@ -15,23 +15,27 @@ public static void main(String[] args) { } /** - * Converts all the characters in this {@code String} to upper case + * Converts all the characters in this {@code String} to upper case. * * @param s the string to convert * @return the {@code String}, converted to uppercase. */ public static String toUpperCase(String s) { if (s == null) { - throw new IllegalArgumentException("Input string connot be null"); + throw new IllegalArgumentException("Input string cannot be null"); } if (s.isEmpty()) { return s; } - StringBuilder result = new StringBuilder(s); - for (int i = 0; i < result.length(); ++i) { - char currentChar = result.charAt(i); - if (Character.isLetter(currentChar) && Character.isLowerCase(currentChar)) { - result.setCharAt(i, Character.toUpperCase(currentChar)); + + StringBuilder result = new StringBuilder(s.length()); + + for (int i = 0; i < s.length(); ++i) { + char currentChar = s.charAt(i); + if (Character.isLowerCase(currentChar)) { + result.append(Character.toUpperCase(currentChar)); + } else { + result.append(currentChar); } } return result.toString(); From 316def4ea65f68ca8982148b97896c8bfef27e87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20S=C3=A1nchez=20N=C3=BA=C3=B1ez?= Date: Sun, 7 Dec 2025 12:18:55 +0100 Subject: [PATCH 66/74] Add Snell's Law refraction algorithm (#7150) * Add Snell's Law implementation for refraction angle * Add tests for Snell's Law calculations * Update documentation with reference link to Snell's Law Added a reference link to Snell's Law in the documentation. * Prevent instantiation of SnellLaw class Make SnellLaw class non-instantiable by adding a private constructor. * Rename SnellsLawTest to SnellLawTest * Refactor SnellLawTest for clarity and accuracy * Rename SnellsLaw.java to SnellLaw.java * Refactor SnellLawTest with additional assertions * Refactor SnellLaw class constructor and error handling Refactor SnellLaw constructor and error message formatting. * Fix missing newline at end of SnellLawTest.java Ensure that the SnellLawTest class has a newline at the end of the file. * Simplify assertions in SnellLawTest * Simplify exception throwing for total internal reflection --- .../com/thealgorithms/physics/SnellLaw.java | 33 +++++++++++++++ .../thealgorithms/physics/SnellLawTest.java | 41 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 src/main/java/com/thealgorithms/physics/SnellLaw.java create mode 100644 src/test/java/com/thealgorithms/physics/SnellLawTest.java diff --git a/src/main/java/com/thealgorithms/physics/SnellLaw.java b/src/main/java/com/thealgorithms/physics/SnellLaw.java new file mode 100644 index 000000000000..2736984814fd --- /dev/null +++ b/src/main/java/com/thealgorithms/physics/SnellLaw.java @@ -0,0 +1,33 @@ +package com.thealgorithms.physics; + +/** + * Calculates refraction angle using Snell's Law: + * n1 * sin(theta1) = n2 * sin(theta2) + * @see Snell's Law + */ +public final class SnellLaw { + + private SnellLaw() { + throw new AssertionError("No instances."); + } + + /** + * Computes the refracted angle (theta2) in radians. + * + * @param n1 index of refraction of medium 1 + * @param n2 index of refraction of medium 2 + * @param theta1 incident angle in radians + * @return refracted angle (theta2) in radians + * @throws IllegalArgumentException if total internal reflection occurs + */ + public static double refractedAngle(double n1, double n2, double theta1) { + double ratio = n1 / n2; + double sinTheta2 = ratio * Math.sin(theta1); + + if (Math.abs(sinTheta2) > 1.0) { + throw new IllegalArgumentException("Total internal reflection: no refraction possible."); + } + + return Math.asin(sinTheta2); + } +} diff --git a/src/test/java/com/thealgorithms/physics/SnellLawTest.java b/src/test/java/com/thealgorithms/physics/SnellLawTest.java new file mode 100644 index 000000000000..ddd5fb1d5af7 --- /dev/null +++ b/src/test/java/com/thealgorithms/physics/SnellLawTest.java @@ -0,0 +1,41 @@ +package com.thealgorithms.physics; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +public class SnellLawTest { + + @Test + public void testRefractedAngle() { + double n1 = 1.0; // air + double n2 = 1.5; // glass + double theta1 = Math.toRadians(30); + + double theta2 = SnellLaw.refractedAngle(n1, n2, theta1); + + double expected = Math.asin(n1 / n2 * Math.sin(theta1)); + + assertEquals(expected, theta2, 1e-12); + } + + @Test + public void testTotalInternalReflection() { + double n1 = 1.5; + double n2 = 1.0; + double theta1 = Math.toRadians(60); // large angle + + assertThrows(IllegalArgumentException.class, () -> SnellLaw.refractedAngle(n1, n2, theta1)); + } + + @Test + public void testNoTotalInternalReflectionAtLowAngles() { + double n1 = 1.5; + double n2 = 1.0; + double theta1 = Math.toRadians(10); + + assertDoesNotThrow(() -> SnellLaw.refractedAngle(n1, n2, theta1)); + } +} From e7c3e1f7739a494d96ded480b167b28ca657f1cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 09:43:17 +0100 Subject: [PATCH 67/74] chore(deps): bump com.mebigfatguy.fb-contrib:fb-contrib from 7.7.1 to 7.7.2 (#7153) chore(deps): bump com.mebigfatguy.fb-contrib:fb-contrib Bumps [com.mebigfatguy.fb-contrib:fb-contrib](https://github.com/mebigfatguy/fb-contrib) from 7.7.1 to 7.7.2. - [Commits](https://github.com/mebigfatguy/fb-contrib/commits/v7.7.2) --- updated-dependencies: - dependency-name: com.mebigfatguy.fb-contrib:fb-contrib dependency-version: 7.7.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dc7d211b2742..4baf7a5f99b0 100644 --- a/pom.xml +++ b/pom.xml @@ -127,7 +127,7 @@ com.mebigfatguy.fb-contrib fb-contrib - 7.7.1 + 7.7.2 com.h3xstream.findsecbugs From 520151ab8e51b502e96cd959ebdfdfff7468aa22 Mon Sep 17 00:00:00 2001 From: codeahl <142953446+codeahl@users.noreply.github.com> Date: Wed, 10 Dec 2025 03:00:28 -0600 Subject: [PATCH 68/74] Add Big-O time and space complexity comments for sorting algorithms (#7155) Add time and space complexity comments for specific sorting algorithms Co-authored-by: Deniz Altunkapan --- .../com/thealgorithms/sorts/BubbleSort.java | 7 +++++++ .../java/com/thealgorithms/sorts/HeapSort.java | 13 ++++++++++++- .../com/thealgorithms/sorts/InsertionSort.java | 18 ++++++++++++++++++ .../com/thealgorithms/sorts/MergeSort.java | 13 +++++++++---- .../com/thealgorithms/sorts/QuickSort.java | 11 +++++++++-- .../com/thealgorithms/sorts/SelectionSort.java | 13 +++++++++---- .../thealgorithms/sorts/TopologicalSort.java | 11 +++++++++-- 7 files changed, 73 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/thealgorithms/sorts/BubbleSort.java b/src/main/java/com/thealgorithms/sorts/BubbleSort.java index 6823c68d0a74..d2eca3506c2d 100644 --- a/src/main/java/com/thealgorithms/sorts/BubbleSort.java +++ b/src/main/java/com/thealgorithms/sorts/BubbleSort.java @@ -10,6 +10,13 @@ class BubbleSort implements SortAlgorithm { /** * Implements generic bubble sort algorithm. * + * Time Complexity: + * - Best case: O(n) – array is already sorted. + * - Average case: O(n^2) + * - Worst case: O(n^2) + * + * Space Complexity: O(1) – in-place sorting. + * * @param array the array to be sorted. * @param the type of elements in the array. * @return the sorted array. diff --git a/src/main/java/com/thealgorithms/sorts/HeapSort.java b/src/main/java/com/thealgorithms/sorts/HeapSort.java index e798fb91b925..5e3b20f43e10 100644 --- a/src/main/java/com/thealgorithms/sorts/HeapSort.java +++ b/src/main/java/com/thealgorithms/sorts/HeapSort.java @@ -1,9 +1,20 @@ package com.thealgorithms.sorts; /** - * Heap Sort Algorithm Implementation + * Heap Sort algorithm implementation. + * + * Heap sort converts the array into a max-heap and repeatedly extracts the maximum + * element to sort the array in increasing order. + * + * Time Complexity: + * - Best case: O(n log n) + * - Average case: O(n log n) + * - Worst case: O(n log n) + * + * Space Complexity: O(1) – in-place sorting * * @see Heap Sort Algorithm + * @see SortAlgorithm */ public class HeapSort implements SortAlgorithm { diff --git a/src/main/java/com/thealgorithms/sorts/InsertionSort.java b/src/main/java/com/thealgorithms/sorts/InsertionSort.java index 21ebf3827b5f..fdbfd9cd1cfa 100644 --- a/src/main/java/com/thealgorithms/sorts/InsertionSort.java +++ b/src/main/java/com/thealgorithms/sorts/InsertionSort.java @@ -1,5 +1,23 @@ package com.thealgorithms.sorts; +/** + * Generic Insertion Sort algorithm. + * + * Standard insertion sort iterates through the array and inserts each element into its + * correct position in the sorted portion of the array. + * + * Sentinel sort is a variation that first places the minimum element at index 0 to + * avoid redundant comparisons in subsequent passes. + * + * Time Complexity: + * - Best case: O(n) – array is already sorted (sentinel sort can improve slightly) + * - Average case: O(n^2) + * - Worst case: O(n^2) – array is reverse sorted + * + * Space Complexity: O(1) – in-place sorting + * + * @see SortAlgorithm + */ class InsertionSort implements SortAlgorithm { /** diff --git a/src/main/java/com/thealgorithms/sorts/MergeSort.java b/src/main/java/com/thealgorithms/sorts/MergeSort.java index 86a184f67b26..f7a7c8da004d 100644 --- a/src/main/java/com/thealgorithms/sorts/MergeSort.java +++ b/src/main/java/com/thealgorithms/sorts/MergeSort.java @@ -13,11 +13,16 @@ class MergeSort implements SortAlgorithm { private Comparable[] aux; /** - * Generic merge sort algorithm implements. + * Generic merge sort algorithm. * - * @param unsorted the array which should be sorted. - * @param Comparable class. - * @return sorted array. + * Time Complexity: + * - Best case: O(n log n) + * - Average case: O(n log n) + * - Worst case: O(n log n) + * + * Space Complexity: O(n) – requires auxiliary array for merging. + * + * @see SortAlgorithm */ @Override public > T[] sort(T[] unsorted) { diff --git a/src/main/java/com/thealgorithms/sorts/QuickSort.java b/src/main/java/com/thealgorithms/sorts/QuickSort.java index 3abb1aae2306..a025e6909259 100644 --- a/src/main/java/com/thealgorithms/sorts/QuickSort.java +++ b/src/main/java/com/thealgorithms/sorts/QuickSort.java @@ -8,9 +8,16 @@ class QuickSort implements SortAlgorithm { /** - * This method implements the Generic Quick Sort + * Generic Quick Sort algorithm. * - * @param array The array to be sorted Sorts the array in increasing order + * Time Complexity: + * - Best case: O(n log n) – pivot splits array roughly in half each time. + * - Average case: O(n log n) + * - Worst case: O(n^2) – occurs when pivot consistently produces unbalanced splits. + * + * Space Complexity: O(log n) – recursion stack, in-place sorting. + * + * @see SortAlgorithm */ @Override public > T[] sort(T[] array) { diff --git a/src/main/java/com/thealgorithms/sorts/SelectionSort.java b/src/main/java/com/thealgorithms/sorts/SelectionSort.java index db7732d7e218..2d1814441701 100644 --- a/src/main/java/com/thealgorithms/sorts/SelectionSort.java +++ b/src/main/java/com/thealgorithms/sorts/SelectionSort.java @@ -2,11 +2,16 @@ public class SelectionSort implements SortAlgorithm { /** - * Sorts an array of comparable elements in increasing order using the selection sort algorithm. + * Generic Selection Sort algorithm. * - * @param array the array to be sorted - * @param the class of array elements - * @return the sorted array + * Time Complexity: + * - Best case: O(n^2) + * - Average case: O(n^2) + * - Worst case: O(n^2) + * + * Space Complexity: O(1) – in-place sorting. + * + * @see SortAlgorithm */ @Override public > T[] sort(T[] array) { diff --git a/src/main/java/com/thealgorithms/sorts/TopologicalSort.java b/src/main/java/com/thealgorithms/sorts/TopologicalSort.java index e4ed240a9947..382ddde9a6f2 100644 --- a/src/main/java/com/thealgorithms/sorts/TopologicalSort.java +++ b/src/main/java/com/thealgorithms/sorts/TopologicalSort.java @@ -11,9 +11,16 @@ * a linked list. A Directed Graph is proven to be acyclic when a DFS or Depth First Search is * performed, yielding no back-edges. * - * https://en.wikipedia.org/wiki/Topological_sorting + * Time Complexity: O(V + E) + * - V: number of vertices + * - E: number of edges * - * @author Jonathan Taylor (https://github.com/Jtmonument) + * Space Complexity: O(V + E) + * - adjacency list and recursion stack in DFS + * + * Reference: https://en.wikipedia.org/wiki/Topological_sorting + * + * Author: Jonathan Taylor (https://github.com/Jtmonument) * Based on Introduction to Algorithms 3rd Edition */ public final class TopologicalSort { From 4f40206684b026f8c0315d8fa419f4951e0500ba Mon Sep 17 00:00:00 2001 From: Lucas Horn <146038502+LucasAHorn@users.noreply.github.com> Date: Wed, 10 Dec 2025 03:04:32 -0600 Subject: [PATCH 69/74] Add unit tests for graph algorithms (#7133) (#7156) * Add unit tests for graph algorithms (BFS, DFS, Dijkstra, Bellman-Ford) #7133 - Created BellmanFordTest.java with 10 test methods covering various graph scenarios - Created ConnectedComponentTest.java with 15 test methods for DFS-based component counting - Enhanced MatrixGraphsTest.java with additional BFS/DFS test cases - Enhanced DijkstraAlgorithmTest.java with comprehensive shortest path tests Fixes #7133 * fix: format files using clang * fix: removing my changes on pull_request_template --------- Co-authored-by: prashantdubeypng --- .../graphs/BellmanFordTest.java | 158 +++++++++++++ .../graphs/ConnectedComponentTest.java | 204 +++++++++++++++++ .../graphs/DijkstraAlgorithmTest.java | 117 ++++++++++ .../graphs/MatrixGraphsTest.java | 211 ++++++++++++++++++ 4 files changed, 690 insertions(+) create mode 100644 src/test/java/com/thealgorithms/datastructures/graphs/BellmanFordTest.java create mode 100644 src/test/java/com/thealgorithms/datastructures/graphs/ConnectedComponentTest.java diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/BellmanFordTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/BellmanFordTest.java new file mode 100644 index 000000000000..c824241c680d --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/graphs/BellmanFordTest.java @@ -0,0 +1,158 @@ +package com.thealgorithms.datastructures.graphs; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.Test; + +/** + * Unit tests for the BellmanFord algorithm implementation. + * Tests cover various graph scenarios including: + * - Simple weighted graphs + * - Graphs with negative weights + * - Single vertex graphs + * - Disconnected graphs + * - Linear path graphs + */ +class BellmanFordTest { + + @Test + void testSimpleGraph() { + // Create a simple graph with 5 vertices and 8 edges + // Graph visualization: + // 1 + // /|\ + // 6 | 7 + // / | \ + // 0 5 2 + // \ | / + // 8 | -2 + // \|/ + // 4---3 + // 9 + BellmanFord bellmanFord = new BellmanFord(5, 8); + bellmanFord.addEdge(0, 1, 6); + bellmanFord.addEdge(0, 4, 8); + bellmanFord.addEdge(1, 2, 7); + bellmanFord.addEdge(1, 4, 5); + bellmanFord.addEdge(2, 3, -2); + bellmanFord.addEdge(2, 4, -3); + bellmanFord.addEdge(3, 4, 9); + bellmanFord.addEdge(4, 3, 7); + + // Verify edge array creation + assertNotNull(bellmanFord.getEdgeArray()); + assertEquals(8, bellmanFord.getEdgeArray().length); + } + + @Test + void testGraphWithNegativeWeights() { + // Graph with negative edge weights (but no negative cycle) + BellmanFord bellmanFord = new BellmanFord(4, 5); + bellmanFord.addEdge(0, 1, 4); + bellmanFord.addEdge(0, 2, 5); + bellmanFord.addEdge(1, 2, -3); + bellmanFord.addEdge(2, 3, 4); + bellmanFord.addEdge(1, 3, 6); + + assertNotNull(bellmanFord.getEdgeArray()); + assertEquals(5, bellmanFord.getEdgeArray().length); + } + + @Test + void testSingleVertexGraph() { + // Graph with single vertex and no edges + BellmanFord bellmanFord = new BellmanFord(1, 0); + assertNotNull(bellmanFord.getEdgeArray()); + assertEquals(0, bellmanFord.getEdgeArray().length); + } + + @Test + void testLinearGraph() { + // Linear graph: 0 -> 1 -> 2 -> 3 + BellmanFord bellmanFord = new BellmanFord(4, 3); + bellmanFord.addEdge(0, 1, 2); + bellmanFord.addEdge(1, 2, 3); + bellmanFord.addEdge(2, 3, 4); + + assertNotNull(bellmanFord.getEdgeArray()); + assertEquals(3, bellmanFord.getEdgeArray().length); + } + + @Test + void testEdgeAddition() { + BellmanFord bellmanFord = new BellmanFord(3, 3); + + bellmanFord.addEdge(0, 1, 5); + bellmanFord.addEdge(1, 2, 3); + bellmanFord.addEdge(0, 2, 10); + + // Verify all edges were added + assertNotNull(bellmanFord.getEdgeArray()); + assertEquals(3, bellmanFord.getEdgeArray().length); + } + + @Test + void testGraphWithZeroWeightEdges() { + // Graph with zero weight edges + BellmanFord bellmanFord = new BellmanFord(3, 3); + bellmanFord.addEdge(0, 1, 0); + bellmanFord.addEdge(1, 2, 0); + bellmanFord.addEdge(0, 2, 1); + + assertNotNull(bellmanFord.getEdgeArray()); + assertEquals(3, bellmanFord.getEdgeArray().length); + } + + @Test + void testLargerGraph() { + // Larger graph with 6 vertices + BellmanFord bellmanFord = new BellmanFord(6, 9); + bellmanFord.addEdge(0, 1, 5); + bellmanFord.addEdge(0, 2, 3); + bellmanFord.addEdge(1, 3, 6); + bellmanFord.addEdge(1, 2, 2); + bellmanFord.addEdge(2, 4, 4); + bellmanFord.addEdge(2, 5, 2); + bellmanFord.addEdge(2, 3, 7); + bellmanFord.addEdge(3, 4, -1); + bellmanFord.addEdge(4, 5, -2); + + assertNotNull(bellmanFord.getEdgeArray()); + assertEquals(9, bellmanFord.getEdgeArray().length); + } + + @Test + void testVertexAndEdgeCount() { + BellmanFord bellmanFord = new BellmanFord(10, 15); + assertEquals(10, bellmanFord.vertex); + assertEquals(15, bellmanFord.edge); + } + + @Test + void testMultipleEdgesBetweenSameVertices() { + // Graph allowing multiple edges between same vertices + BellmanFord bellmanFord = new BellmanFord(2, 3); + bellmanFord.addEdge(0, 1, 5); + bellmanFord.addEdge(0, 1, 3); + bellmanFord.addEdge(1, 0, 2); + + assertNotNull(bellmanFord.getEdgeArray()); + assertEquals(3, bellmanFord.getEdgeArray().length); + } + + @Test + void testCompleteGraph() { + // Complete graph with 4 vertices (6 edges for undirected equivalent) + BellmanFord bellmanFord = new BellmanFord(4, 6); + bellmanFord.addEdge(0, 1, 1); + bellmanFord.addEdge(0, 2, 2); + bellmanFord.addEdge(0, 3, 3); + bellmanFord.addEdge(1, 2, 4); + bellmanFord.addEdge(1, 3, 5); + bellmanFord.addEdge(2, 3, 6); + + assertNotNull(bellmanFord.getEdgeArray()); + assertEquals(6, bellmanFord.getEdgeArray().length); + } +} diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/ConnectedComponentTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/ConnectedComponentTest.java new file mode 100644 index 000000000000..b5cfdd9de04f --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/graphs/ConnectedComponentTest.java @@ -0,0 +1,204 @@ +package com.thealgorithms.datastructures.graphs; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.Test; + +/** + * Unit tests for the Graph class in ConnectedComponent.java. + * Tests the depth-first search implementation and connected component counting. + * Covers various graph topologies including: + * - Single connected components + * - Multiple disconnected components + * - Self-loops + * - Linear chains + * - Cyclic graphs + */ +class ConnectedComponentTest { + + @Test + void testSingleConnectedComponent() { + Graph graph = new Graph<>(); + graph.addEdge(1, 2); + graph.addEdge(2, 3); + graph.addEdge(3, 4); + graph.addEdge(4, 1); + + assertEquals(1, graph.countGraphs()); + } + + @Test + void testTwoDisconnectedComponents() { + Graph graph = new Graph<>(); + // Component 1: 1-2-3 + graph.addEdge(1, 2); + graph.addEdge(2, 3); + // Component 2: 4-5 + graph.addEdge(4, 5); + + assertEquals(2, graph.countGraphs()); + } + + @Test + void testThreeDisconnectedComponents() { + Graph graph = new Graph<>(); + // Component 1: a-b-c-d-e + graph.addEdge('a', 'b'); + graph.addEdge('a', 'e'); + graph.addEdge('b', 'e'); + graph.addEdge('b', 'c'); + graph.addEdge('c', 'd'); + graph.addEdge('d', 'a'); + // Component 2: x-y-z + graph.addEdge('x', 'y'); + graph.addEdge('x', 'z'); + // Component 3: w (self-loop) + graph.addEdge('w', 'w'); + + assertEquals(3, graph.countGraphs()); + } + + @Test + void testSingleNodeSelfLoop() { + Graph graph = new Graph<>(); + graph.addEdge(1, 1); + + assertEquals(1, graph.countGraphs()); + } + + @Test + void testLinearChain() { + Graph graph = new Graph<>(); + graph.addEdge(1, 2); + graph.addEdge(2, 3); + graph.addEdge(3, 4); + graph.addEdge(4, 5); + + assertEquals(1, graph.countGraphs()); + } + + @Test + void testStarTopology() { + // Star graph with center node 0 connected to nodes 1, 2, 3, 4 + Graph graph = new Graph<>(); + graph.addEdge(0, 1); + graph.addEdge(0, 2); + graph.addEdge(0, 3); + graph.addEdge(0, 4); + + assertEquals(1, graph.countGraphs()); + } + + @Test + void testCompleteGraph() { + // Complete graph K4: every node connected to every other node + Graph graph = new Graph<>(); + graph.addEdge(1, 2); + graph.addEdge(1, 3); + graph.addEdge(1, 4); + graph.addEdge(2, 3); + graph.addEdge(2, 4); + graph.addEdge(3, 4); + + assertEquals(1, graph.countGraphs()); + } + + @Test + void testStringVertices() { + Graph graph = new Graph<>(); + // Component 1 + graph.addEdge("New York", "Los Angeles"); + graph.addEdge("Los Angeles", "Chicago"); + // Component 2 + graph.addEdge("London", "Paris"); + // Component 3 + graph.addEdge("Tokyo", "Tokyo"); + + assertEquals(3, graph.countGraphs()); + } + + @Test + void testEmptyGraph() { + Graph graph = new Graph<>(); + assertEquals(0, graph.countGraphs()); + } + + @Test + void testDepthFirstSearchBasic() { + Graph graph = new Graph<>(); + graph.addEdge(1, 2); + graph.addEdge(2, 3); + + // Get the first node and perform DFS + assertNotNull(graph.nodeList); + assertEquals(3, graph.nodeList.size()); + } + + @Test + void testManyIsolatedComponents() { + Graph graph = new Graph<>(); + // Create 5 isolated components (each is a self-loop) + graph.addEdge(1, 1); + graph.addEdge(2, 2); + graph.addEdge(3, 3); + graph.addEdge(4, 4); + graph.addEdge(5, 5); + + assertEquals(5, graph.countGraphs()); + } + + @Test + void testBidirectionalEdges() { + Graph graph = new Graph<>(); + // Note: This is a directed graph representation + // Adding edge 1->2 does not automatically add 2->1 + graph.addEdge(1, 2); + graph.addEdge(2, 1); + graph.addEdge(2, 3); + graph.addEdge(3, 2); + + assertEquals(1, graph.countGraphs()); + } + + @Test + void testCyclicGraph() { + Graph graph = new Graph<>(); + // Create a cycle: 1 -> 2 -> 3 -> 4 -> 1 + graph.addEdge(1, 2); + graph.addEdge(2, 3); + graph.addEdge(3, 4); + graph.addEdge(4, 1); + + assertEquals(1, graph.countGraphs()); + } + + @Test + void testMultipleCycles() { + Graph graph = new Graph<>(); + // Cycle 1: 1 -> 2 -> 3 -> 1 + graph.addEdge(1, 2); + graph.addEdge(2, 3); + graph.addEdge(3, 1); + // Cycle 2: 4 -> 5 -> 4 + graph.addEdge(4, 5); + graph.addEdge(5, 4); + + assertEquals(2, graph.countGraphs()); + } + + @Test + void testIntegerGraphFromMainExample() { + // Recreate the example from main method + Graph graph = new Graph<>(); + graph.addEdge(1, 2); + graph.addEdge(2, 3); + graph.addEdge(2, 4); + graph.addEdge(3, 5); + graph.addEdge(7, 8); + graph.addEdge(8, 10); + graph.addEdge(10, 8); + + assertEquals(2, graph.countGraphs()); + } +} diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java index c5df9acdf33b..a189091c17d3 100644 --- a/src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java +++ b/src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java @@ -1,6 +1,7 @@ package com.thealgorithms.datastructures.graphs; import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.BeforeEach; @@ -61,4 +62,120 @@ void testInvalidSourceVertex() { assertThrows(IllegalArgumentException.class, () -> dijkstraAlgorithm.run(graph, -1)); assertThrows(IllegalArgumentException.class, () -> dijkstraAlgorithm.run(graph, graph.length)); } + + @Test + void testLinearGraph() { + // Linear graph: 0 - 1 - 2 - 3 + // with weights: 2 3 4 + int[][] linearGraph = {{0, 2, 0, 0}, {2, 0, 3, 0}, {0, 3, 0, 4}, {0, 0, 4, 0}}; + + DijkstraAlgorithm dijkstraLinear = new DijkstraAlgorithm(4); + int[] distances = dijkstraLinear.run(linearGraph, 0); + + assertArrayEquals(new int[] {0, 2, 5, 9}, distances); + } + + @Test + void testStarTopology() { + // Star graph: center node 0 connected to all others + // 1(2) + // | + // 3(4)-0-2(3) + // | + // 4(5) + int[][] starGraph = {{0, 2, 3, 4, 5}, {2, 0, 0, 0, 0}, {3, 0, 0, 0, 0}, {4, 0, 0, 0, 0}, {5, 0, 0, 0, 0}}; + + DijkstraAlgorithm dijkstraStar = new DijkstraAlgorithm(5); + int[] distances = dijkstraStar.run(starGraph, 0); + + assertArrayEquals(new int[] {0, 2, 3, 4, 5}, distances); + } + + @Test + void testCompleteGraphK4() { + // Complete graph K4 with varying weights + int[][] completeGraph = {{0, 1, 2, 3}, {1, 0, 4, 5}, {2, 4, 0, 6}, {3, 5, 6, 0}}; + + DijkstraAlgorithm dijkstraComplete = new DijkstraAlgorithm(4); + int[] distances = dijkstraComplete.run(completeGraph, 0); + + // Direct paths from 0 are shortest + assertArrayEquals(new int[] {0, 1, 2, 3}, distances); + } + + @Test + void testDifferentSourceVertex() { + // Test running from different source vertices + int[][] simpleGraph = {{0, 5, 0, 0}, {5, 0, 3, 0}, {0, 3, 0, 2}, {0, 0, 2, 0}}; + + DijkstraAlgorithm dijkstra = new DijkstraAlgorithm(4); + + // From vertex 0 + int[] distFrom0 = dijkstra.run(simpleGraph, 0); + assertArrayEquals(new int[] {0, 5, 8, 10}, distFrom0); + + // From vertex 2 + int[] distFrom2 = dijkstra.run(simpleGraph, 2); + assertArrayEquals(new int[] {8, 3, 0, 2}, distFrom2); + + // From vertex 3 + int[] distFrom3 = dijkstra.run(simpleGraph, 3); + assertArrayEquals(new int[] {10, 5, 2, 0}, distFrom3); + } + + @Test + void testUnitWeightGraph() { + // Graph with all unit weights (like BFS distance) + int[][] unitGraph = {{0, 1, 1, 0}, {1, 0, 1, 1}, {1, 1, 0, 1}, {0, 1, 1, 0}}; + + DijkstraAlgorithm dijkstraUnit = new DijkstraAlgorithm(4); + int[] distances = dijkstraUnit.run(unitGraph, 0); + + assertArrayEquals(new int[] {0, 1, 1, 2}, distances); + } + + @Test + void testTwoVertexGraph() { + int[][] twoVertexGraph = {{0, 7}, {7, 0}}; + + DijkstraAlgorithm dijkstraTwo = new DijkstraAlgorithm(2); + int[] distances = dijkstraTwo.run(twoVertexGraph, 0); + + assertArrayEquals(new int[] {0, 7}, distances); + } + + @Test + void testShortcutPath() { + // Graph where direct path is longer than indirect path + // 0 --(10)--> 2 + // 0 --(1)--> 1 --(2)--> 2 + int[][] shortcutGraph = {{0, 1, 10}, {1, 0, 2}, {10, 2, 0}}; + + DijkstraAlgorithm dijkstraShortcut = new DijkstraAlgorithm(3); + int[] distances = dijkstraShortcut.run(shortcutGraph, 0); + + // The shortest path to vertex 2 should be 3 (via vertex 1), not 10 (direct) + assertArrayEquals(new int[] {0, 1, 3}, distances); + } + + @Test + void testSourceToSourceDistanceIsZero() { + // Verify distance from source to itself is always 0 + int[] distances = dijkstraAlgorithm.run(graph, 0); + assertEquals(0, distances[0]); + + distances = dijkstraAlgorithm.run(graph, 5); + assertEquals(0, distances[5]); + } + + @Test + void testLargeWeights() { + // Graph with large weights + int[][] largeWeightGraph = {{0, 1000, 0}, {1000, 0, 2000}, {0, 2000, 0}}; + + DijkstraAlgorithm dijkstraLarge = new DijkstraAlgorithm(3); + int[] distances = dijkstraLarge.run(largeWeightGraph, 0); + + assertArrayEquals(new int[] {0, 1000, 3000}, distances); + } } diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/MatrixGraphsTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/MatrixGraphsTest.java index cc8a2df872ce..eaff0222bd36 100644 --- a/src/test/java/com/thealgorithms/datastructures/graphs/MatrixGraphsTest.java +++ b/src/test/java/com/thealgorithms/datastructures/graphs/MatrixGraphsTest.java @@ -137,4 +137,215 @@ void testDisconnectedGraph() { assertTrue(dfs.containsAll(Arrays.asList(0, 1))); assertTrue(bfs.containsAll(Arrays.asList(0, 1))); } + + @Test + void testSingleVertexGraphDfs() { + AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(1); + + List dfs = graph.depthFirstOrder(0); + assertEquals(1, dfs.size()); + assertEquals(0, dfs.getFirst()); + } + + @Test + void testSingleVertexGraphBfs() { + AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(1); + + List bfs = graph.breadthFirstOrder(0); + assertEquals(1, bfs.size()); + assertEquals(0, bfs.getFirst()); + } + + @Test + void testBfsLevelOrder() { + // Create a graph where BFS should visit level by level + // 0 + // /|\ + // 1 2 3 + // | + // 4 + AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5); + graph.addEdge(0, 1); + graph.addEdge(0, 2); + graph.addEdge(0, 3); + graph.addEdge(1, 4); + + List bfs = graph.breadthFirstOrder(0); + assertEquals(5, bfs.size()); + assertEquals(0, bfs.get(0)); + // Level 1 vertices (1, 2, 3) should appear before level 2 vertex (4) + int indexOf4 = bfs.indexOf(4); + assertTrue(bfs.indexOf(1) < indexOf4); + assertTrue(bfs.indexOf(2) < indexOf4); + assertTrue(bfs.indexOf(3) < indexOf4); + } + + @Test + void testDfsStartFromDifferentVertices() { + AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(4); + graph.addEdge(0, 1); + graph.addEdge(1, 2); + graph.addEdge(2, 3); + + // DFS from vertex 0 + List dfs0 = graph.depthFirstOrder(0); + assertEquals(4, dfs0.size()); + assertEquals(0, dfs0.get(0)); + + // DFS from vertex 2 + List dfs2 = graph.depthFirstOrder(2); + assertEquals(4, dfs2.size()); + assertEquals(2, dfs2.get(0)); + + // DFS from vertex 3 + List dfs3 = graph.depthFirstOrder(3); + assertEquals(4, dfs3.size()); + assertEquals(3, dfs3.get(0)); + } + + @Test + void testBfsStartFromDifferentVertices() { + AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(4); + graph.addEdge(0, 1); + graph.addEdge(1, 2); + graph.addEdge(2, 3); + + // BFS from vertex 0 + List bfs0 = graph.breadthFirstOrder(0); + assertEquals(4, bfs0.size()); + assertEquals(0, bfs0.get(0)); + + // BFS from vertex 2 + List bfs2 = graph.breadthFirstOrder(2); + assertEquals(4, bfs2.size()); + assertEquals(2, bfs2.get(0)); + } + + @Test + void testStarTopologyBfs() { + // Star graph: 0 is center connected to 1, 2, 3, 4 + AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5); + graph.addEdge(0, 1); + graph.addEdge(0, 2); + graph.addEdge(0, 3); + graph.addEdge(0, 4); + + List bfs = graph.breadthFirstOrder(0); + assertEquals(5, bfs.size()); + assertEquals(0, bfs.get(0)); + // All neighbors should be at distance 1 + assertTrue(bfs.containsAll(Arrays.asList(1, 2, 3, 4))); + } + + @Test + void testStarTopologyDfs() { + // Star graph: 0 is center connected to 1, 2, 3, 4 + AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5); + graph.addEdge(0, 1); + graph.addEdge(0, 2); + graph.addEdge(0, 3); + graph.addEdge(0, 4); + + List dfs = graph.depthFirstOrder(0); + assertEquals(5, dfs.size()); + assertEquals(0, dfs.get(0)); + assertTrue(dfs.containsAll(Arrays.asList(1, 2, 3, 4))); + } + + @Test + void testNegativeStartVertexDfs() { + AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5); + graph.addEdge(0, 1); + + List dfs = graph.depthFirstOrder(-1); + assertTrue(dfs.isEmpty()); + } + + @Test + void testNegativeStartVertexBfs() { + AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5); + graph.addEdge(0, 1); + + List bfs = graph.breadthFirstOrder(-1); + assertTrue(bfs.isEmpty()); + } + + @Test + void testCompleteGraphKFour() { + // Complete graph K4: every vertex connected to every other vertex + AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(4); + graph.addEdge(0, 1); + graph.addEdge(0, 2); + graph.addEdge(0, 3); + graph.addEdge(1, 2); + graph.addEdge(1, 3); + graph.addEdge(2, 3); + + assertEquals(6, graph.numberOfEdges()); + + List dfs = graph.depthFirstOrder(0); + List bfs = graph.breadthFirstOrder(0); + + assertEquals(4, dfs.size()); + assertEquals(4, bfs.size()); + assertTrue(dfs.containsAll(Arrays.asList(0, 1, 2, 3))); + assertTrue(bfs.containsAll(Arrays.asList(0, 1, 2, 3))); + } + + @Test + void testLargerGraphTraversal() { + // Create a larger graph with 10 vertices + AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(10); + graph.addEdge(0, 1); + graph.addEdge(0, 2); + graph.addEdge(1, 3); + graph.addEdge(1, 4); + graph.addEdge(2, 5); + graph.addEdge(2, 6); + graph.addEdge(3, 7); + graph.addEdge(4, 8); + graph.addEdge(5, 9); + + List dfs = graph.depthFirstOrder(0); + List bfs = graph.breadthFirstOrder(0); + + assertEquals(10, dfs.size()); + assertEquals(10, bfs.size()); + assertEquals(0, dfs.get(0)); + assertEquals(0, bfs.get(0)); + } + + @Test + void testSelfLoop() { + AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(3); + graph.addEdge(0, 0); // Self loop + graph.addEdge(0, 1); + graph.addEdge(1, 2); + + List dfs = graph.depthFirstOrder(0); + List bfs = graph.breadthFirstOrder(0); + + assertEquals(3, dfs.size()); + assertEquals(3, bfs.size()); + } + + @Test + void testLinearGraphTraversal() { + // Linear graph: 0 - 1 - 2 - 3 - 4 + AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5); + graph.addEdge(0, 1); + graph.addEdge(1, 2); + graph.addEdge(2, 3); + graph.addEdge(3, 4); + + List dfs = graph.depthFirstOrder(0); + List bfs = graph.breadthFirstOrder(0); + + assertEquals(5, dfs.size()); + assertEquals(5, bfs.size()); + + // In a linear graph, BFS and DFS starting from 0 should be the same + assertEquals(Arrays.asList(0, 1, 2, 3, 4), dfs); + assertEquals(Arrays.asList(0, 1, 2, 3, 4), bfs); + } } From a8bc9cc5258f68ced843b827cbabb1b60e80f35d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 10:33:35 +0000 Subject: [PATCH 70/74] chore(deps-dev): bump org.mockito:mockito-core from 5.20.0 to 5.21.0 (#7154) Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.20.0 to 5.21.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.20.0...v5.21.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-version: 5.21.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Deniz Altunkapan --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4baf7a5f99b0..185249a0ea0f 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ org.mockito mockito-core - 5.20.0 + 5.21.0 test From 746457ce152909a76613cdd7ba69b0e7acd72e5b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 Dec 2025 00:29:17 +0100 Subject: [PATCH 71/74] chore(deps): bump actions/cache from 4 to 5 in /.github/workflows (#7162) Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/cache dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/infer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/infer.yml b/.github/workflows/infer.yml index c85b1d225f72..9d4dcf63000b 100644 --- a/.github/workflows/infer.yml +++ b/.github/workflows/infer.yml @@ -33,7 +33,7 @@ jobs: - name: Cache infer build id: cache-infer - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: infer key: ${{ runner.os }}-infer-${{ env.year_week }} From bccaf970baf8f7caa7ae08c0088e224625d8d5f0 Mon Sep 17 00:00:00 2001 From: utkarsh patel <153971829+Utkarsh-patel26@users.noreply.github.com> Date: Sun, 14 Dec 2025 15:38:18 +0530 Subject: [PATCH 72/74] Add Z-Algorithm for Linear-Time String Pattern Matching (#7124) * Add Z-Algorithm (string pattern matching) with tests * Add Z-Algorithm (string pattern matching) with tests * Add Z-Algorithm (string pattern matching) with tests * Fix checkstyle errors for ZAlgorithm * Fix: clang-format and checkstyle compliance for ZAlgorithm --- DIRECTORY.md | 2 + .../com/thealgorithms/strings/ZAlgorithm.java | 48 +++++++++++++++++++ .../thealgorithms/strings/ZAlgorithmTest.java | 25 ++++++++++ 3 files changed, 75 insertions(+) create mode 100644 src/main/java/com/thealgorithms/strings/ZAlgorithm.java create mode 100644 src/test/java/com/thealgorithms/strings/ZAlgorithmTest.java diff --git a/DIRECTORY.md b/DIRECTORY.md index b8db96ffa993..6ea83fc6a60a 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -822,6 +822,7 @@ - 📄 [Upper](src/main/java/com/thealgorithms/strings/Upper.java) - 📄 [ValidParentheses](src/main/java/com/thealgorithms/strings/ValidParentheses.java) - 📄 [WordLadder](src/main/java/com/thealgorithms/strings/WordLadder.java) + - 📄 [ZAlgorithm](src/main/java/com/thealgorithms/strings/ZAlgorithm.java) - 📁 **zigZagPattern** - 📄 [ZigZagPattern](src/main/java/com/thealgorithms/strings/zigZagPattern/ZigZagPattern.java) - 📁 **tree** @@ -1579,6 +1580,7 @@ - 📄 [UpperTest](src/test/java/com/thealgorithms/strings/UpperTest.java) - 📄 [ValidParenthesesTest](src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java) - 📄 [WordLadderTest](src/test/java/com/thealgorithms/strings/WordLadderTest.java) + - 📄 [ZAlgorithmTest](src/test/java/com/thealgorithms/strings/ZAlgorithmTest.java) - 📁 **zigZagPattern** - 📄 [ZigZagPatternTest](src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java) - 📁 **tree** diff --git a/src/main/java/com/thealgorithms/strings/ZAlgorithm.java b/src/main/java/com/thealgorithms/strings/ZAlgorithm.java new file mode 100644 index 000000000000..dc029b751f45 --- /dev/null +++ b/src/main/java/com/thealgorithms/strings/ZAlgorithm.java @@ -0,0 +1,48 @@ +/* + * https://en.wikipedia.org/wiki/Z-algorithm + */ +package com.thealgorithms.strings; + +public final class ZAlgorithm { + + private ZAlgorithm() { + throw new UnsupportedOperationException("Utility class"); + } + + public static int[] zFunction(String s) { + int n = s.length(); + int[] z = new int[n]; + int l = 0; + int r = 0; + + for (int i = 1; i < n; i++) { + if (i <= r) { + z[i] = Math.min(r - i + 1, z[i - l]); + } + + while (i + z[i] < n && s.charAt(z[i]) == s.charAt(i + z[i])) { + z[i]++; + } + + if (i + z[i] - 1 > r) { + l = i; + r = i + z[i] - 1; + } + } + + return z; + } + + public static int search(String text, String pattern) { + String s = pattern + "$" + text; + int[] z = zFunction(s); + int p = pattern.length(); + + for (int i = 0; i < z.length; i++) { + if (z[i] == p) { + return i - p - 1; + } + } + return -1; + } +} diff --git a/src/test/java/com/thealgorithms/strings/ZAlgorithmTest.java b/src/test/java/com/thealgorithms/strings/ZAlgorithmTest.java new file mode 100644 index 000000000000..df749ed9a8b5 --- /dev/null +++ b/src/test/java/com/thealgorithms/strings/ZAlgorithmTest.java @@ -0,0 +1,25 @@ +package com.thealgorithms.strings; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class ZAlgorithmTest { + + @Test + void testZFunction() { + int[] z = ZAlgorithm.zFunction("aaaaa"); + assertArrayEquals(new int[] {0, 4, 3, 2, 1}, z); + } + + @Test + void testSearchFound() { + assertEquals(2, ZAlgorithm.search("abcabca", "cab")); + } + + @Test + void testSearchNotFound() { + assertEquals(-1, ZAlgorithm.search("abcdef", "gh")); + } +} From aa914512030269fd30173cd3892804bac203aded Mon Sep 17 00:00:00 2001 From: Muhammad Junaid Khalid Date: Sun, 14 Dec 2025 15:14:00 +0500 Subject: [PATCH 73/74] feat: Binary Tree to String algorithm added (Leetcode 606) (#6727) * feat: BinaryTreeToString.java Added with tests * fix: javadoc added to BinaryTreeToString * fix: link to leetcode added --- .../trees/BinaryTreeToString.java | 100 ++++++++++++++++++ .../trees/BinaryTreeToStringTest.java | 57 ++++++++++ 2 files changed, 157 insertions(+) create mode 100644 src/main/java/com/thealgorithms/datastructures/trees/BinaryTreeToString.java create mode 100644 src/test/java/com/thealgorithms/datastructures/trees/BinaryTreeToStringTest.java diff --git a/src/main/java/com/thealgorithms/datastructures/trees/BinaryTreeToString.java b/src/main/java/com/thealgorithms/datastructures/trees/BinaryTreeToString.java new file mode 100644 index 000000000000..2f9b3b489d56 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/trees/BinaryTreeToString.java @@ -0,0 +1,100 @@ +package com.thealgorithms.datastructures.trees; + +/** + * Leetcode 606: Construct String from Binary Tree: + * https://leetcode.com/problems/construct-string-from-binary-tree/ + * + * Utility class to convert a {@link BinaryTree} into its string representation. + *

+ * The conversion follows a preorder traversal pattern (root → left → right) + * and uses parentheses to denote the tree structure. + * Empty parentheses "()" are used to explicitly represent missing left children + * when a right child exists, ensuring the structure is unambiguous. + *

+ * + *

Rules:

+ *
    + *
  • Each node is represented as {@code (value)}.
  • + *
  • If a node has only a right child, include {@code ()} before the right + * child + * to indicate the missing left child.
  • + *
  • If a node has no children, it appears as just {@code (value)}.
  • + *
  • The outermost parentheses are removed from the final string.
  • + *
+ * + *

Example:

+ * + *
+ *     Input tree:
+ *           1
+ *          / \
+ *         2   3
+ *          \
+ *           4
+ *
+ *     Output string:
+ *     "1(2()(4))(3)"
+ * 
+ * + *

+ * This implementation matches the logic from LeetCode problem 606: + * Construct String from Binary Tree. + *

+ * + * @author Muhammad Junaid + * @see BinaryTree + */ +public class BinaryTreeToString { + + /** String builder used to accumulate the string representation. */ + private StringBuilder sb; + + /** + * Converts a binary tree (given its root node) to its string representation. + * + * @param root the root node of the binary tree + * @return the string representation of the binary tree, or an empty string if + * the tree is null + */ + public String tree2str(BinaryTree.Node root) { + if (root == null) { + return ""; + } + + sb = new StringBuilder(); + dfs(root); + + // Remove the leading and trailing parentheses added by the root call + return sb.substring(1, sb.length() - 1); + } + + /** + * Performs a recursive depth-first traversal to build the string. + * Each recursive call appends the node value and its children (if any) + * enclosed in parentheses. + * + * @param node the current node being processed + */ + private void dfs(BinaryTree.Node node) { + if (node == null) { + return; + } + + sb.append("(").append(node.data); + + // Recursively build left and right subtrees + if (node.left != null) { + dfs(node.left); + } + + // Handle the special case: right child exists but left child is null + if (node.right != null && node.left == null) { + sb.append("()"); + dfs(node.right); + } else if (node.right != null) { + dfs(node.right); + } + + sb.append(")"); + } +} diff --git a/src/test/java/com/thealgorithms/datastructures/trees/BinaryTreeToStringTest.java b/src/test/java/com/thealgorithms/datastructures/trees/BinaryTreeToStringTest.java new file mode 100644 index 000000000000..2461fd74143d --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/trees/BinaryTreeToStringTest.java @@ -0,0 +1,57 @@ +package com.thealgorithms.datastructures.trees; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * Tests for the BinaryTreeToString class. + */ +public class BinaryTreeToStringTest { + + @Test + public void testTreeToStringBasic() { + BinaryTree tree = new BinaryTree(); + tree.put(1); + tree.put(2); + tree.put(3); + tree.put(4); + + BinaryTreeToString converter = new BinaryTreeToString(); + String result = converter.tree2str(tree.getRoot()); + + // Output will depend on insertion logic of BinaryTree.put() + // which is BST-style, so result = "1()(2()(3()(4)))" + Assertions.assertEquals("1()(2()(3()(4)))", result); + } + + @Test + public void testSingleNodeTree() { + BinaryTree tree = new BinaryTree(); + tree.put(10); + + BinaryTreeToString converter = new BinaryTreeToString(); + String result = converter.tree2str(tree.getRoot()); + + Assertions.assertEquals("10", result); + } + + @Test + public void testComplexTreeStructure() { + BinaryTree.Node root = new BinaryTree.Node(10); + root.left = new BinaryTree.Node(5); + root.right = new BinaryTree.Node(20); + root.right.left = new BinaryTree.Node(15); + root.right.right = new BinaryTree.Node(25); + + BinaryTreeToString converter = new BinaryTreeToString(); + String result = converter.tree2str(root); + + Assertions.assertEquals("10(5)(20(15)(25))", result); + } + + @Test + public void testNullTree() { + BinaryTreeToString converter = new BinaryTreeToString(); + Assertions.assertEquals("", converter.tree2str(null)); + } +} From d9f2ac8340946f4c677a3ea1a5b9128a533086e0 Mon Sep 17 00:00:00 2001 From: Taranjeet Singh Kalsi Date: Sun, 14 Dec 2025 15:59:14 +0530 Subject: [PATCH 74/74] Added program to check Lucky number (#6962) added program for lucky number --- .../com/thealgorithms/maths/LuckyNumber.java | 78 +++++++++++++++++++ .../thealgorithms/maths/LuckyNumberTest.java | 32 ++++++++ 2 files changed, 110 insertions(+) create mode 100644 src/main/java/com/thealgorithms/maths/LuckyNumber.java create mode 100644 src/test/java/com/thealgorithms/maths/LuckyNumberTest.java diff --git a/src/main/java/com/thealgorithms/maths/LuckyNumber.java b/src/main/java/com/thealgorithms/maths/LuckyNumber.java new file mode 100644 index 000000000000..70308e1e0edd --- /dev/null +++ b/src/main/java/com/thealgorithms/maths/LuckyNumber.java @@ -0,0 +1,78 @@ +package com.thealgorithms.maths; + +/** + * In number theory, a lucky number is a natural number in a set which is generated by a certain "sieve". + * This sieve is similar to the sieve of Eratosthenes that generates the primes, + * but it eliminates numbers based on their position in the remaining set, + * instead of their value (or position in the initial set of natural numbers). + * + * Wiki: https://en.wikipedia.org/wiki/Lucky_number + */ +public final class LuckyNumber { + + private LuckyNumber() { + } + + // Common validation method + private static void validatePositiveNumber(int number) { + if (number <= 0) { + throw new IllegalArgumentException("Number must be positive."); + } + } + + // Function to check recursively for Lucky Number + private static boolean isLuckyRecursiveApproach(int n, int counter) { + // Base case: If counter exceeds n, number is lucky + if (counter > n) { + return true; + } + + // If number is eliminated in this step, it's not lucky + if (n % counter == 0) { + return false; + } + + // Calculate new position after removing every counter-th number + int newNumber = n - (n / counter); + + // Recursive call for next round + return isLuckyRecursiveApproach(newNumber, counter + 1); + } + + /** + * Check if {@code number} is a Lucky number or not using recursive approach + * + * @param number the number + * @return {@code true} if {@code number} is a Lucky number, otherwise false + */ + public static boolean isLuckyNumber(int number) { + validatePositiveNumber(number); + int counterStarting = 2; + return isLuckyRecursiveApproach(number, counterStarting); + } + + /** + * Check if {@code number} is a Lucky number or not using iterative approach + * + * @param number the number + * @return {@code true} if {@code number} is a Lucky number, otherwise false + */ + public static boolean isLucky(int number) { + validatePositiveNumber(number); + + int counter = 2; // Position starts from 2 (since first elimination happens at 2) + int position = number; // The position of the number in the sequence + + while (counter <= position) { + if (position % counter == 0) { + return false; + } // Number is eliminated + + // Update the position of n after removing every counter-th number + position = position - (position / counter); + counter++; + } + + return true; // Survives all eliminations → Lucky Number + } +} diff --git a/src/test/java/com/thealgorithms/maths/LuckyNumberTest.java b/src/test/java/com/thealgorithms/maths/LuckyNumberTest.java new file mode 100644 index 000000000000..91904316b25c --- /dev/null +++ b/src/test/java/com/thealgorithms/maths/LuckyNumberTest.java @@ -0,0 +1,32 @@ +package com.thealgorithms.maths; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +class LuckyNumberTest { + + @ParameterizedTest + @CsvSource({"1", "3", "13", "49", "109", "459", "949"}) + void luckyNumbersTest(int n) { + assertTrue(LuckyNumber.isLucky(n)); + assertTrue(LuckyNumber.isLuckyNumber(n)); + } + + @ParameterizedTest + @CsvSource({"2", "17", "100", "300", "700"}) + void nonLuckyNumbersTest(int n) { + assertFalse(LuckyNumber.isLucky(n)); + assertFalse(LuckyNumber.isLuckyNumber(n)); + } + + @ParameterizedTest + @CsvSource({"0", "-1"}) + void throwsNegativeNumbersNotAllowed(int n) { + assertThrows(IllegalArgumentException.class, () -> LuckyNumber.isLucky(n)); + assertThrows(IllegalArgumentException.class, () -> LuckyNumber.isLuckyNumber(n)); + } +}