From fd0bcb79e61743e96e837a48e2fc9a54efd08a42 Mon Sep 17 00:00:00 2001
From: Ahmed Allam <60698204+GziXnine@users.noreply.github.com>
Date: Fri, 16 Jan 2026 13:33:29 +0200
Subject: [PATCH 01/58] Add Middle of Linked List (Slow/Fast Pointers) (#7212)
* feat: implement Smooth Sort algorithm with detailed JavaDoc and test class
* style: format LEONARDO array for improved readability with clang-format
* feat: add MiddleOfLinkedList class and corresponding test cases
* docs: update documentation for MiddleOfLinkedList class
* test: refactor MiddleOfLinkedListTest to improve readability and assertions
* test: refactor MiddleOfLinkedListTest for improved null safety and readability
---------
Co-authored-by: Ahmed Allam <60698204+AllamF5J@users.noreply.github.com>
---
.../lists/MiddleOfLinkedList.java | 46 ++++++++++++
.../lists/MiddleOfLinkedListTest.java | 74 +++++++++++++++++++
2 files changed, 120 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedList.java
create mode 100644 src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java
diff --git a/src/main/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedList.java b/src/main/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedList.java
new file mode 100644
index 000000000000..0ee788db2ff9
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedList.java
@@ -0,0 +1,46 @@
+package com.thealgorithms.datastructures.lists;
+
+/**
+ * Returns the middle node of a singly linked list using the two-pointer technique.
+ *
+ *
The {@code slow} pointer advances by one node per iteration while {@code fast} advances by two.
+ * When {@code fast == null} or {@code fast.next == null}, {@code slow} points to the middle node.
+ * For even-length lists, this returns the second middle node.
+ *
+ * This method does not modify the input list.
+ *
+ * Reference: https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoise_and_hare
+ *
+ * Complexity:
+ *
+ * - Time: {@code O(n)}
+ * - Space: {@code O(1)}
+ *
+ */
+public final class MiddleOfLinkedList {
+
+ private MiddleOfLinkedList() {
+ }
+
+ /**
+ * Returns the middle node of the list.
+ *
+ * @param head the head of the singly linked list; may be {@code null}
+ * @return the middle node (second middle for even-sized lists), or {@code null} if {@code head} is {@code null}
+ */
+ public static SinglyLinkedListNode middleNode(final SinglyLinkedListNode head) {
+ if (head == null) {
+ return null;
+ }
+
+ SinglyLinkedListNode slow = head;
+ SinglyLinkedListNode fast = head;
+
+ while (fast != null && fast.next != null) {
+ slow = slow.next;
+ fast = fast.next.next;
+ }
+
+ return slow;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java
new file mode 100644
index 000000000000..ba5614a07916
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java
@@ -0,0 +1,74 @@
+package com.thealgorithms.datastructures.lists;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import java.util.Objects;
+import org.junit.jupiter.api.Test;
+
+public class MiddleOfLinkedListTest {
+
+ private static SinglyLinkedListNode listOf(int firstValue, int... remainingValues) {
+ SinglyLinkedListNode head = new SinglyLinkedListNode(firstValue);
+ SinglyLinkedListNode current = head;
+
+ for (int i = 0; i < remainingValues.length; i++) {
+ current.next = new SinglyLinkedListNode(remainingValues[i]);
+ current = current.next;
+ }
+ return head;
+ }
+
+ @Test
+ void middleNodeOddLength() {
+ SinglyLinkedListNode head = listOf(1, 2, 3, 4, 5);
+ SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(head));
+ assertEquals(3, middle.value);
+ }
+
+ @Test
+ void middleNodeEvenLengthReturnsSecondMiddle() {
+ SinglyLinkedListNode head = listOf(1, 2, 3, 4, 5, 6);
+ SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(head));
+ assertEquals(4, middle.value);
+ }
+
+ @Test
+ void middleNodeSingleElement() {
+ SinglyLinkedListNode head = listOf(42);
+ SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(head));
+ assertEquals(42, middle.value);
+ }
+
+ @Test
+ void middleNodeTwoElementsReturnsSecond() {
+ SinglyLinkedListNode head = listOf(10, 20);
+ SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(head));
+ assertEquals(20, middle.value);
+ }
+
+ @Test
+ void middleNodeNullHead() {
+ assertNull(MiddleOfLinkedList.middleNode(null));
+ }
+
+ @Test
+ void middleNodeDoesNotModifyListStructure() {
+ SinglyLinkedListNode first = new SinglyLinkedListNode(1);
+ SinglyLinkedListNode second = new SinglyLinkedListNode(2);
+ SinglyLinkedListNode third = new SinglyLinkedListNode(3);
+ SinglyLinkedListNode fourth = new SinglyLinkedListNode(4);
+
+ first.next = second;
+ second.next = third;
+ third.next = fourth;
+
+ SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(first));
+ assertEquals(3, middle.value);
+
+ assertEquals(second, first.next);
+ assertEquals(third, second.next);
+ assertEquals(fourth, third.next);
+ assertNull(fourth.next);
+ }
+}
From 782d0755d584c9f5c9931ff6f03976144e10c279 Mon Sep 17 00:00:00 2001
From: SwaatiR <85189166+SwaatiR@users.noreply.github.com>
Date: Sat, 17 Jan 2026 23:48:54 +0530
Subject: [PATCH 02/58] Improve documentation for Linear Search algorithm
(#7214)
---
.../thealgorithms/searches/LinearSearch.java | 23 +++++++++++--------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/src/main/java/com/thealgorithms/searches/LinearSearch.java b/src/main/java/com/thealgorithms/searches/LinearSearch.java
index c7b70edb5112..cb483d8dfedc 100644
--- a/src/main/java/com/thealgorithms/searches/LinearSearch.java
+++ b/src/main/java/com/thealgorithms/searches/LinearSearch.java
@@ -1,21 +1,26 @@
package com.thealgorithms.searches;
import com.thealgorithms.devutils.searches.SearchAlgorithm;
-
/**
- * Linear search is the easiest search algorithm It works with sorted and
- * unsorted arrays (an binary search works only with sorted array) This
- * algorithm just compares all elements of an array to find a value
+ * Linear Search is a simple searching algorithm that checks
+ * each element of the array sequentially until the target
+ * value is found or the array ends.
+ *
+ * It works for both sorted and unsorted arrays.
*
- *
- * Worst-case performance O(n) Best-case performance O(1) Average performance
- * O(n) Worst-case space complexity
+ * Time Complexity:
+ * - Best case: O(1)
+ * - Average case: O(n)
+ * - Worst case: O(n)
*
- * @author Varun Upadhyay (https://github.com/varunu28)
- * @author Podshivalov Nikita (https://github.com/nikitap492)
+ * Space Complexity: O(1)
+ *
+ * @author Varun Upadhyay
+ * @author Podshivalov Nikita
* @see BinarySearch
* @see SearchAlgorithm
*/
+
public class LinearSearch implements SearchAlgorithm {
/**
From 48f6322b385f12e8b052d1e04e7d1acdd765b982 Mon Sep 17 00:00:00 2001
From: Chahat Sandhu
Date: Sat, 17 Jan 2026 12:22:11 -0600
Subject: [PATCH 03/58] docs: add Javadoc to FibonacciSeries (#7215)
* docs: add Javadoc to FibonacciSeries
* fix: make small adjustment
---------
Co-authored-by: Deniz Altunkapan
---
.../recursion/FibonacciSeries.java | 22 ++++++++++++++-----
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/src/main/java/com/thealgorithms/recursion/FibonacciSeries.java b/src/main/java/com/thealgorithms/recursion/FibonacciSeries.java
index 9bc6da2f7443..9c809858099e 100644
--- a/src/main/java/com/thealgorithms/recursion/FibonacciSeries.java
+++ b/src/main/java/com/thealgorithms/recursion/FibonacciSeries.java
@@ -1,16 +1,26 @@
package com.thealgorithms.recursion;
-/*
- The Fibonacci series is a sequence of numbers where each number is the sum of the two preceding ones,
- starting with 0 and 1.
- NUMBER 0 1 2 3 4 5 6 7 8 9 10 ...
- FIBONACCI 0 1 1 2 3 5 8 13 21 34 55 ...
-*/
+/**
+ * The Fibonacci series is a sequence of numbers where each number is the sum of the two preceding ones,
+ * starting with 0 and 1.
+ *
+ * Example:
+ * 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ...
+ *
+ */
public final class FibonacciSeries {
private FibonacciSeries() {
throw new UnsupportedOperationException("Utility class");
}
+
+ /**
+ * Calculates the nth term in the Fibonacci sequence using recursion.
+ *
+ * @param n the position in the Fibonacci sequence (must be non-negative)
+ * @return the nth Fibonacci number
+ * @throws IllegalArgumentException if n is negative
+ */
public static int fibonacci(int n) {
if (n < 0) {
throw new IllegalArgumentException("n must be a non-negative integer");
From 79cdb98193cb34fa32d9bbad06c21a0d0f356bb3 Mon Sep 17 00:00:00 2001
From: SwaatiR <85189166+SwaatiR@users.noreply.github.com>
Date: Sun, 18 Jan 2026 21:31:01 +0530
Subject: [PATCH 04/58] Add input validation and clarify sorted array
requirement in Binary Search (#7216)
Added input validation and clarify sorted array rrequirement in Binary Search
---
src/main/java/com/thealgorithms/searches/BinarySearch.java | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/searches/BinarySearch.java b/src/main/java/com/thealgorithms/searches/BinarySearch.java
index bedad1667f33..0cac484d56b4 100644
--- a/src/main/java/com/thealgorithms/searches/BinarySearch.java
+++ b/src/main/java/com/thealgorithms/searches/BinarySearch.java
@@ -5,7 +5,9 @@
/**
* Binary search is one of the most popular algorithms The algorithm finds the
* position of a target value within a sorted array
- *
+ * IMPORTANT
+ * This algorithm works correctly only if the input array is sorted
+ * in ascending order.
*
* Worst-case performance O(log n) Best-case performance O(1) Average
* performance O(log n) Worst-case space complexity O(1)
@@ -25,6 +27,9 @@ class BinarySearch implements SearchAlgorithm {
*/
@Override
public > int find(T[] array, T key) {
+ if (array == null || array.length == 0) {
+ return -1;
+ }
return search(array, key, 0, array.length - 1);
}
From 1b9373e71a9a3e8e9f1b4f3f2338aee419ee2c1e Mon Sep 17 00:00:00 2001
From: Chahat Sandhu
Date: Mon, 19 Jan 2026 03:59:58 -0600
Subject: [PATCH 05/58] feat: add Bell Numbers algorithm using Aitken's Array
(#7219)
* feat: added Bell Numbers algorithm using Aitken's Array
* style: applied clang-format fixes
---
.../com/thealgorithms/maths/BellNumbers.java | 59 +++++++++++++++++++
.../thealgorithms/maths/BellNumbersTest.java | 53 +++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/maths/BellNumbers.java
create mode 100644 src/test/java/com/thealgorithms/maths/BellNumbersTest.java
diff --git a/src/main/java/com/thealgorithms/maths/BellNumbers.java b/src/main/java/com/thealgorithms/maths/BellNumbers.java
new file mode 100644
index 000000000000..d4dc1014f48b
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/BellNumbers.java
@@ -0,0 +1,59 @@
+package com.thealgorithms.maths;
+
+/**
+ * The Bell numbers count the number of partitions of a set.
+ * The n-th Bell number is the number of ways a set of n elements can be partitioned
+ * into nonempty subsets.
+ *
+ *
+ * This implementation uses the Bell Triangle (Aitken's array) method.
+ * Time Complexity: O(n^2)
+ * Space Complexity: O(n^2)
+ *
+ *
+ * @author Chahat Sandhu, singhc7
+ * @see Bell Number (Wikipedia)
+ */
+public final class BellNumbers {
+
+ private BellNumbers() {
+ }
+
+ /**
+ * Calculates the n-th Bell number using the Bell Triangle.
+ *
+ * @param n the index of the Bell number (must be non-negative)
+ * @return the n-th Bell number
+ * @throws IllegalArgumentException if n is negative or n > 25
+ */
+ public static long compute(int n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("n must be non-negative");
+ }
+ if (n == 0) {
+ return 1;
+ }
+ if (n > 25) {
+ throw new IllegalArgumentException("n must be <= 25. For larger n, use BigInteger implementation.");
+ }
+
+ // We use a 2D array to visualize the Bell Triangle
+ long[][] bellTriangle = new long[n + 1][n + 1];
+
+ // Base case: The triangle starts with 1
+ bellTriangle[0][0] = 1;
+
+ for (int i = 1; i <= n; i++) {
+ // Rule 1: The first number in a new row is the LAST number of the previous row
+ bellTriangle[i][0] = bellTriangle[i - 1][i - 1];
+
+ // Rule 2: Fill the rest of the row by adding the previous neighbor and the upper-left neighbor
+ for (int j = 1; j <= i; j++) {
+ bellTriangle[i][j] = bellTriangle[i][j - 1] + bellTriangle[i - 1][j - 1];
+ }
+ }
+
+ // The Bell number B_n is the first number in the n-th row
+ return bellTriangle[n][0];
+ }
+}
diff --git a/src/test/java/com/thealgorithms/maths/BellNumbersTest.java b/src/test/java/com/thealgorithms/maths/BellNumbersTest.java
new file mode 100644
index 000000000000..8dd83cf0f7a9
--- /dev/null
+++ b/src/test/java/com/thealgorithms/maths/BellNumbersTest.java
@@ -0,0 +1,53 @@
+package com.thealgorithms.maths;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+class BellNumbersTest {
+
+ @Test
+ void testStandardCases() {
+ // Base cases and small numbers
+ assertEquals(1, BellNumbers.compute(0));
+ assertEquals(1, BellNumbers.compute(1));
+ assertEquals(2, BellNumbers.compute(2));
+ assertEquals(5, BellNumbers.compute(3));
+ assertEquals(15, BellNumbers.compute(4));
+ assertEquals(52, BellNumbers.compute(5));
+ }
+
+ @Test
+ void testMediumNumber() {
+ // B10 = 115,975
+ assertEquals(115975, BellNumbers.compute(10));
+ // B15 = 1,382,958,545
+ assertEquals(1382958545L, BellNumbers.compute(15));
+ }
+
+ @Test
+ void testLargeNumber() {
+ // B20 = 51,724,158,235,372
+ // We use the 'L' suffix to tell Java this is a long literal
+ assertEquals(51724158235372L, BellNumbers.compute(20));
+ }
+
+ @Test
+ void testMaxLongCapacity() {
+ // B25 is the largest Bell number that fits in a Java long (signed 64-bit)
+ // B25 = 4,638,590,332,229,999,353
+ assertEquals(4638590332229999353L, BellNumbers.compute(25));
+ }
+
+ @Test
+ void testNegativeInput() {
+ assertThrows(IllegalArgumentException.class, () -> BellNumbers.compute(-1));
+ }
+
+ @Test
+ void testOverflowProtection() {
+ // We expect an exception if the user asks for the impossible
+ assertThrows(IllegalArgumentException.class, () -> BellNumbers.compute(26));
+ }
+}
From 109ed2e49743df52cb6aad1a5cfc496432ae3d10 Mon Sep 17 00:00:00 2001
From: Chahat Sandhu
Date: Mon, 19 Jan 2026 04:15:59 -0600
Subject: [PATCH 06/58] feat: Add Prefix Sum category with 1D and 2D
implementations (#7220)
Co-authored-by: Deniz Altunkapan
---
.../thealgorithms/prefixsum/PrefixSum.java | 54 +++++++++++
.../thealgorithms/prefixsum/PrefixSum2D.java | 64 +++++++++++++
.../prefixsum/PrefixSum2DTest.java | 92 +++++++++++++++++++
.../prefixsum/PrefixSumTest.java | 80 ++++++++++++++++
4 files changed, 290 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/prefixsum/PrefixSum.java
create mode 100644 src/main/java/com/thealgorithms/prefixsum/PrefixSum2D.java
create mode 100644 src/test/java/com/thealgorithms/prefixsum/PrefixSum2DTest.java
create mode 100644 src/test/java/com/thealgorithms/prefixsum/PrefixSumTest.java
diff --git a/src/main/java/com/thealgorithms/prefixsum/PrefixSum.java b/src/main/java/com/thealgorithms/prefixsum/PrefixSum.java
new file mode 100644
index 000000000000..47f6366e2924
--- /dev/null
+++ b/src/main/java/com/thealgorithms/prefixsum/PrefixSum.java
@@ -0,0 +1,54 @@
+package com.thealgorithms.prefixsum;
+
+/**
+ * A class that implements the Prefix Sum algorithm.
+ *
+ * Prefix Sum is a technique used to preprocess an array such that
+ * range sum queries can be answered in O(1) time.
+ * The preprocessing step takes O(N) time.
+ *
+ *
This implementation uses a long array for the prefix sums to prevent
+ * integer overflow when the sum of elements exceeds Integer.MAX_VALUE.
+ *
+ * @see Prefix Sum (Wikipedia)
+ * @author Chahat Sandhu, singhc7
+ */
+public class PrefixSum {
+
+ private final long[] prefixSums;
+
+ /**
+ * Constructor to preprocess the input array.
+ *
+ * @param array The input integer array.
+ * @throws IllegalArgumentException if the array is null.
+ */
+ public PrefixSum(int[] array) {
+ if (array == null) {
+ throw new IllegalArgumentException("Input array cannot be null");
+ }
+ this.prefixSums = new long[array.length + 1];
+ this.prefixSums[0] = 0;
+
+ for (int i = 0; i < array.length; i++) {
+ // Automatically promotes int to long during addition
+ this.prefixSums[i + 1] = this.prefixSums[i] + array[i];
+ }
+ }
+
+ /**
+ * Calculates the sum of elements in the range [left, right].
+ * Indices are 0-based.
+ *
+ * @param left The starting index (inclusive).
+ * @param right The ending index (inclusive).
+ * @return The sum of elements from index left to right as a long.
+ * @throws IndexOutOfBoundsException if indices are out of valid range.
+ */
+ public long sumRange(int left, int right) {
+ if (left < 0 || right >= prefixSums.length - 1 || left > right) {
+ throw new IndexOutOfBoundsException("Invalid range indices");
+ }
+ return prefixSums[right + 1] - prefixSums[left];
+ }
+}
diff --git a/src/main/java/com/thealgorithms/prefixsum/PrefixSum2D.java b/src/main/java/com/thealgorithms/prefixsum/PrefixSum2D.java
new file mode 100644
index 000000000000..9c168bc6bcc4
--- /dev/null
+++ b/src/main/java/com/thealgorithms/prefixsum/PrefixSum2D.java
@@ -0,0 +1,64 @@
+package com.thealgorithms.prefixsum;
+
+/**
+ * A class that implements the 2D Prefix Sum algorithm.
+ *
+ *
2D Prefix Sum is a technique used to preprocess a 2D matrix such that
+ * sub-matrix sum queries can be answered in O(1) time.
+ * The preprocessing step takes O(N*M) time.
+ *
+ *
This implementation uses a long array for the prefix sums to prevent
+ * integer overflow.
+ *
+ * @see Summed-area table (Wikipedia)
+ * @author Chahat Sandhu, singhc7
+ */
+public class PrefixSum2D {
+
+ private final long[][] prefixSums;
+
+ /**
+ * Constructor to preprocess the input matrix.
+ *
+ * @param matrix The input integer matrix.
+ * @throws IllegalArgumentException if the matrix is null or empty.
+ */
+ public PrefixSum2D(int[][] matrix) {
+ if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
+ throw new IllegalArgumentException("Input matrix cannot be null or empty");
+ }
+
+ int rows = matrix.length;
+ int cols = matrix[0].length;
+ this.prefixSums = new long[rows + 1][cols + 1];
+
+ for (int i = 0; i < rows; i++) {
+ for (int j = 0; j < cols; j++) {
+ // P[i+1][j+1] = current + above + left - diagonal_overlap
+ this.prefixSums[i + 1][j + 1] = matrix[i][j] + this.prefixSums[i][j + 1] + this.prefixSums[i + 1][j] - this.prefixSums[i][j];
+ }
+ }
+ }
+
+ /**
+ * Calculates the sum of the sub-matrix defined by (row1, col1) to (row2, col2).
+ * Indices are 0-based.
+ *
+ * @param row1 Top row index.
+ * @param col1 Left column index.
+ * @param row2 Bottom row index.
+ * @param col2 Right column index.
+ * @return The sum of the sub-matrix.
+ * @throws IndexOutOfBoundsException if indices are invalid.
+ */
+ public long sumRegion(int row1, int col1, int row2, int col2) {
+ if (row1 < 0 || row2 >= prefixSums.length - 1 || row2 < row1) {
+ throw new IndexOutOfBoundsException("Invalid row indices");
+ }
+ if (col1 < 0 || col2 >= prefixSums[0].length - 1 || col2 < col1) {
+ throw new IndexOutOfBoundsException("Invalid column indices");
+ }
+
+ return prefixSums[row2 + 1][col2 + 1] - prefixSums[row1][col2 + 1] - prefixSums[row2 + 1][col1] + prefixSums[row1][col1];
+ }
+}
diff --git a/src/test/java/com/thealgorithms/prefixsum/PrefixSum2DTest.java b/src/test/java/com/thealgorithms/prefixsum/PrefixSum2DTest.java
new file mode 100644
index 000000000000..87feff859356
--- /dev/null
+++ b/src/test/java/com/thealgorithms/prefixsum/PrefixSum2DTest.java
@@ -0,0 +1,92 @@
+package com.thealgorithms.prefixsum;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+class PrefixSum2DTest {
+
+ @Test
+ @DisplayName("Test basic 3x3 square matrix")
+ void testStandardSquare() {
+ int[][] matrix = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
+ PrefixSum2D ps = new PrefixSum2D(matrix);
+
+ // Sum of top-left 2x2: {1,2, 4,5} -> 12
+ assertEquals(12L, ps.sumRegion(0, 0, 1, 1));
+ // Sum of bottom-right 2x2: {5,6, 8,9} -> 28
+ assertEquals(28L, ps.sumRegion(1, 1, 2, 2));
+ // Full matrix -> 45
+ assertEquals(45L, ps.sumRegion(0, 0, 2, 2));
+ }
+
+ @Test
+ @DisplayName("Test rectangular matrix (more cols than rows)")
+ void testRectangularWide() {
+ int[][] matrix = {{1, 1, 1, 1}, {2, 2, 2, 2}};
+ PrefixSum2D ps = new PrefixSum2D(matrix);
+
+ // Sum of first 3 columns of both rows -> (1*3) + (2*3) = 9
+ assertEquals(9L, ps.sumRegion(0, 0, 1, 2));
+ }
+
+ @Test
+ @DisplayName("Test rectangular matrix (more rows than cols)")
+ void testRectangularTall() {
+ int[][] matrix = {{1}, {2}, {3}, {4}};
+ PrefixSum2D ps = new PrefixSum2D(matrix);
+
+ // Sum of middle two elements -> 2+3 = 5
+ assertEquals(5L, ps.sumRegion(1, 0, 2, 0));
+ }
+
+ @Test
+ @DisplayName("Test single element matrix")
+ void testSingleElement() {
+ int[][] matrix = {{100}};
+ PrefixSum2D ps = new PrefixSum2D(matrix);
+
+ assertEquals(100L, ps.sumRegion(0, 0, 0, 0));
+ }
+
+ @Test
+ @DisplayName("Test large numbers for overflow (Integer -> Long)")
+ void testLargeNumbers() {
+ // 2 billion. Two of these sum to > MAX_INT
+ int val = 2_000_000_000;
+ int[][] matrix = {{val, val}, {val, val}};
+ PrefixSum2D ps = new PrefixSum2D(matrix);
+
+ // 4 * 2B = 8 Billion
+ assertEquals(8_000_000_000L, ps.sumRegion(0, 0, 1, 1));
+ }
+
+ @Test
+ @DisplayName("Test invalid inputs")
+ void testInvalidInputs() {
+ assertThrows(IllegalArgumentException.class, () -> new PrefixSum2D(null));
+ assertThrows(IllegalArgumentException.class, () -> new PrefixSum2D(new int[][] {})); // empty
+ assertThrows(IllegalArgumentException.class, () -> new PrefixSum2D(new int[][] {{}})); // empty row
+ }
+
+ @Test
+ @DisplayName("Test invalid query ranges")
+ void testInvalidRanges() {
+ int[][] matrix = {{1, 2}, {3, 4}};
+ PrefixSum2D ps = new PrefixSum2D(matrix);
+
+ // Negative indices
+ assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRegion(-1, 0, 0, 0));
+ assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRegion(0, -1, 0, 0));
+
+ // Out of bounds
+ assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRegion(0, 0, 2, 0)); // row2 too big
+ assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRegion(0, 0, 0, 2)); // col2 too big
+
+ // Inverted ranges (start > end)
+ assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRegion(1, 0, 0, 0)); // row1 > row2
+ assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRegion(0, 1, 0, 0)); // col1 > col2
+ }
+}
diff --git a/src/test/java/com/thealgorithms/prefixsum/PrefixSumTest.java b/src/test/java/com/thealgorithms/prefixsum/PrefixSumTest.java
new file mode 100644
index 000000000000..a421b62e9306
--- /dev/null
+++ b/src/test/java/com/thealgorithms/prefixsum/PrefixSumTest.java
@@ -0,0 +1,80 @@
+package com.thealgorithms.prefixsum;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+class PrefixSumTest {
+
+ @Test
+ @DisplayName("Test basic sum with positive integers")
+ void testStandardCase() {
+ int[] input = {1, 2, 3, 4, 5};
+ PrefixSum ps = new PrefixSum(input);
+
+ // Sum of range [0, 4] -> 15
+ assertEquals(15L, ps.sumRange(0, 4));
+
+ // Sum of range [1, 3] -> 9
+ assertEquals(9L, ps.sumRange(1, 3));
+ }
+
+ @Test
+ @DisplayName("Test array with negative numbers and zeros")
+ void testNegativeAndZeros() {
+ int[] input = {-2, 0, 3, -5, 2, -1};
+ PrefixSum ps = new PrefixSum(input);
+
+ assertEquals(1L, ps.sumRange(0, 2));
+ assertEquals(-1L, ps.sumRange(2, 5));
+ assertEquals(0L, ps.sumRange(1, 1));
+ }
+
+ @Test
+ @DisplayName("Test with large integers to verify overflow handling")
+ void testLargeNumbers() {
+ // Two values that fit in int, but their sum exceeds Integer.MAX_VALUE
+ // Integer.MAX_VALUE is approx 2.14 billion.
+ int val = 2_000_000_000;
+ int[] input = {val, val, val};
+ PrefixSum ps = new PrefixSum(input);
+
+ // Sum of three 2 billion values is 6 billion (fits in long, overflows int)
+ assertEquals(6_000_000_000L, ps.sumRange(0, 2));
+ }
+
+ @Test
+ @DisplayName("Test single element array")
+ void testSingleElement() {
+ int[] input = {42};
+ PrefixSum ps = new PrefixSum(input);
+ assertEquals(42L, ps.sumRange(0, 0));
+ }
+
+ @Test
+ @DisplayName("Test constructor with null input")
+ void testNullInput() {
+ assertThrows(IllegalArgumentException.class, () -> new PrefixSum(null));
+ }
+
+ @Test
+ @DisplayName("Test empty array behavior")
+ void testEmptyArray() {
+ int[] input = {};
+ PrefixSum ps = new PrefixSum(input);
+ assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRange(0, 0));
+ }
+
+ @Test
+ @DisplayName("Test invalid range indices")
+ void testInvalidIndices() {
+ int[] input = {10, 20, 30};
+ PrefixSum ps = new PrefixSum(input);
+
+ assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRange(-1, 1));
+ assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRange(0, 3));
+ assertThrows(IndexOutOfBoundsException.class, () -> ps.sumRange(2, 1));
+ }
+}
From 7339b9dfe9f8dc1e516866c6e159bedbf8de2198 Mon Sep 17 00:00:00 2001
From: Gopesh Pandey
Date: Tue, 20 Jan 2026 02:06:03 +0530
Subject: [PATCH 07/58] Add distance between two points algorithm (#7218)
* Add distance between two points algorithm
* Create DistanceBetweenTwoPointsTest.java
* DistanceBetweenTwoPoints.java
* Fix test file package and project structure
* Delete src/test/java/com/thealgorithms/DistanceBetweenTwoPointsTest.java
* Apply clang-format compliant formatting
* Apply clang-format
---------
Co-authored-by: a <19151554+alxkm@users.noreply.github.com>
---
.../maths/DistanceBetweenTwoPoints.java | 33 +++++++++++++++++++
.../maths/DistanceBetweenTwoPointsTest.java | 23 +++++++++++++
2 files changed, 56 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/maths/DistanceBetweenTwoPoints.java
create mode 100644 src/test/java/com/thealgorithms/maths/DistanceBetweenTwoPointsTest.java
diff --git a/src/main/java/com/thealgorithms/maths/DistanceBetweenTwoPoints.java b/src/main/java/com/thealgorithms/maths/DistanceBetweenTwoPoints.java
new file mode 100644
index 000000000000..cd1c9205b328
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/DistanceBetweenTwoPoints.java
@@ -0,0 +1,33 @@
+package com.thealgorithms.maths;
+
+/**
+ * Distance Between Two Points in 2D Space.
+ *
+ * This class provides a method to calculate the Euclidean distance between two points in a
+ * two-dimensional plane.
+ *
+ *
Formula: d = sqrt((x2 - x1)^2 + (y2 - y1)^2)
+ *
+ *
Reference: https://en.wikipedia.org/wiki/Euclidean_distance
+ */
+public final class DistanceBetweenTwoPoints {
+
+ private DistanceBetweenTwoPoints() {
+ // Utility class; prevent instantiation
+ }
+
+ /**
+ * Calculate the Euclidean distance between two points.
+ *
+ * @param x1 x-coordinate of the first point
+ * @param y1 y-coordinate of the first point
+ * @param x2 x-coordinate of the second point
+ * @param y2 y-coordinate of the second point
+ * @return Euclidean distance between the two points
+ */
+ public static double calculate(final double x1, final double y1, final double x2, final double y2) {
+ final double deltaX = x2 - x1;
+ final double deltaY = y2 - y1;
+ return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/maths/DistanceBetweenTwoPointsTest.java b/src/test/java/com/thealgorithms/maths/DistanceBetweenTwoPointsTest.java
new file mode 100644
index 000000000000..6bd124629740
--- /dev/null
+++ b/src/test/java/com/thealgorithms/maths/DistanceBetweenTwoPointsTest.java
@@ -0,0 +1,23 @@
+package com.thealgorithms.maths;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+class DistanceBetweenTwoPointsTest {
+
+ @Test
+ void testDistanceSimple() {
+ assertEquals(5.0, DistanceBetweenTwoPoints.calculate(0, 0, 3, 4), 1e-9);
+ }
+
+ @Test
+ void testDistanceNegativeCoordinates() {
+ assertEquals(5.0, DistanceBetweenTwoPoints.calculate(-1, -1, 2, 3), 1e-9);
+ }
+
+ @Test
+ void testSamePoint() {
+ assertEquals(0.0, DistanceBetweenTwoPoints.calculate(2, 2, 2, 2), 1e-9);
+ }
+}
From ba5ccbe0c74330c34e3b643f23828fbd78505d96 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 20 Jan 2026 12:38:12 +0000
Subject: [PATCH 08/58] chore(deps-dev): bump
com.mebigfatguy.fb-contrib:fb-contrib from 7.7.3 to 7.7.4 (#7222)
* chore(deps-dev): bump com.mebigfatguy.fb-contrib:fb-contrib
Bumps [com.mebigfatguy.fb-contrib:fb-contrib](https://github.com/mebigfatguy/fb-contrib) from 7.7.3 to 7.7.4.
- [Commits](https://github.com/mebigfatguy/fb-contrib/compare/v7.7.3...v7.7.4)
---
updated-dependencies:
- dependency-name: com.mebigfatguy.fb-contrib:fb-contrib
dependency-version: 7.7.4
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
* fix: supporess 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 | 21 +++++++++++++++++++++
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index a685e334460c..3f81e66d35c0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -127,7 +127,7 @@
com.mebigfatguy.fb-contrib
fb-contrib
- 7.7.3
+ 7.7.4
com.h3xstream.findsecbugs
diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml
index 3e2f1ff84ca8..9269e3a87e88 100644
--- a/spotbugs-exclude.xml
+++ b/spotbugs-exclude.xml
@@ -207,6 +207,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From 1b014a2ea470ac41363443aaca90eec424411622 Mon Sep 17 00:00:00 2001
From: Piotr Idzik <65706193+vil02@users.noreply.github.com>
Date: Tue, 20 Jan 2026 22:02:10 +0100
Subject: [PATCH 09/58] style: include
`UTAO_JUNIT_ASSERTION_ODDITIES_USE_ASSERT_NULL` (#7225)
---
spotbugs-exclude.xml | 3 ---
.../thealgorithms/ciphers/PermutationCipherTest.java | 5 +++--
.../thealgorithms/datastructures/trees/TreapTest.java | 3 ++-
.../LongestCommonSubsequenceTest.java | 10 ++++------
4 files changed, 9 insertions(+), 12 deletions(-)
diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml
index 9269e3a87e88..f89bad8bebaf 100644
--- a/spotbugs-exclude.xml
+++ b/spotbugs-exclude.xml
@@ -222,9 +222,6 @@
-
-
-
diff --git a/src/test/java/com/thealgorithms/ciphers/PermutationCipherTest.java b/src/test/java/com/thealgorithms/ciphers/PermutationCipherTest.java
index 4ba6787cc97e..ecb7455c1ba2 100644
--- a/src/test/java/com/thealgorithms/ciphers/PermutationCipherTest.java
+++ b/src/test/java/com/thealgorithms/ciphers/PermutationCipherTest.java
@@ -1,6 +1,7 @@
package com.thealgorithms.ciphers;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
@@ -121,8 +122,8 @@ void testNullString() {
String decrypted = cipher.decrypt(encrypted, key);
// then
- assertEquals(null, encrypted);
- assertEquals(null, decrypted);
+ assertNull(encrypted);
+ assertNull(decrypted);
}
@Test
diff --git a/src/test/java/com/thealgorithms/datastructures/trees/TreapTest.java b/src/test/java/com/thealgorithms/datastructures/trees/TreapTest.java
index 09ada594faca..52b74a7a1faf 100644
--- a/src/test/java/com/thealgorithms/datastructures/trees/TreapTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/trees/TreapTest.java
@@ -2,6 +2,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
import org.junit.jupiter.api.Test;
@@ -30,7 +31,7 @@ public void searchAndNotFound() {
treap.insert(3);
treap.insert(8);
treap.insert(1);
- assertEquals(null, treap.search(4));
+ assertNull(treap.search(4));
}
@Test
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java
index 40bbdff15ca6..91169c4cc9d8 100644
--- a/src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java
@@ -1,6 +1,7 @@
package com.thealgorithms.dynamicprogramming;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
import org.junit.jupiter.api.Test;
@@ -55,27 +56,24 @@ public void testLCSWithBothEmptyStrings() {
public void testLCSWithNullFirstString() {
String str1 = null;
String str2 = "XYZ";
- String expected = null; // Should return null if first string is null
String result = LongestCommonSubsequence.getLCS(str1, str2);
- assertEquals(expected, result);
+ assertNull(result);
}
@Test
public void testLCSWithNullSecondString() {
String str1 = "ABC";
String str2 = null;
- String expected = null; // Should return null if second string is null
String result = LongestCommonSubsequence.getLCS(str1, str2);
- assertEquals(expected, result);
+ assertNull(result);
}
@Test
public void testLCSWithNullBothStrings() {
String str1 = null;
String str2 = null;
- String expected = null; // Should return null if both strings are null
String result = LongestCommonSubsequence.getLCS(str1, str2);
- assertEquals(expected, result);
+ assertNull(result);
}
@Test
From 0e8291e66900b48e4be236121a63147e3dcf6b5f Mon Sep 17 00:00:00 2001
From: Piotr Idzik <65706193+vil02@users.noreply.github.com>
Date: Wed, 21 Jan 2026 10:55:09 +0100
Subject: [PATCH 10/58] style: include
`UTAO_JUNIT_ASSERTION_ODDITIES_USE_ASSERT_NOT_NULL` (#7226)
---
spotbugs-exclude.xml | 3 ---
.../thealgorithms/datastructures/heaps/HeapElementTest.java | 3 ++-
.../maths/LinearDiophantineEquationsSolverTest.java | 4 ++--
3 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml
index f89bad8bebaf..410c1f8c5566 100644
--- a/spotbugs-exclude.xml
+++ b/spotbugs-exclude.xml
@@ -219,9 +219,6 @@
-
-
-
diff --git a/src/test/java/com/thealgorithms/datastructures/heaps/HeapElementTest.java b/src/test/java/com/thealgorithms/datastructures/heaps/HeapElementTest.java
index d04a9de8a94b..792969200c82 100644
--- a/src/test/java/com/thealgorithms/datastructures/heaps/HeapElementTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/heaps/HeapElementTest.java
@@ -2,6 +2,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import org.junit.jupiter.api.Test;
@@ -39,7 +40,7 @@ void testEquals() {
assertEquals(element1, element2); // Same key and info
assertNotEquals(element1, element3); // Different key
- assertNotEquals(null, element1); // Check for null
+ assertNotNull(element1);
assertNotEquals("String", element1); // Check for different type
}
diff --git a/src/test/java/com/thealgorithms/maths/LinearDiophantineEquationsSolverTest.java b/src/test/java/com/thealgorithms/maths/LinearDiophantineEquationsSolverTest.java
index c4205985dbfd..885382e29ca2 100644
--- a/src/test/java/com/thealgorithms/maths/LinearDiophantineEquationsSolverTest.java
+++ b/src/test/java/com/thealgorithms/maths/LinearDiophantineEquationsSolverTest.java
@@ -176,7 +176,7 @@ void testSolutionEquality() {
assertEquals(solution1, solution2);
assertNotEquals(solution3, solution1);
assertEquals(solution1, solution1);
- assertNotEquals(null, solution1);
+ assertNotNull(solution1);
assertNotEquals("string", solution1);
}
@@ -217,7 +217,7 @@ void testGcdSolutionWrapperEquality() {
assertEquals(wrapper1, wrapper2);
assertNotEquals(wrapper3, wrapper1);
assertEquals(wrapper1, wrapper1);
- assertNotEquals(null, wrapper1);
+ assertNotNull(wrapper1);
assertNotEquals("string", wrapper1);
}
From 0f9139dc42bd9beb86837bd854e7b13d46a961c8 Mon Sep 17 00:00:00 2001
From: Piotr Idzik <65706193+vil02@users.noreply.github.com>
Date: Thu, 22 Jan 2026 09:24:45 +0100
Subject: [PATCH 11/58] style: include
`UTAO_JUNIT_ASSERTION_ODDITIES_USE_ASSERT_NOT_EQUALS` (#7229)
---
spotbugs-exclude.xml | 3 ---
.../com/thealgorithms/maths/VolumeTest.java | 20 +++++++++----------
2 files changed, 10 insertions(+), 13 deletions(-)
diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml
index 410c1f8c5566..c8a7f71cd880 100644
--- a/spotbugs-exclude.xml
+++ b/spotbugs-exclude.xml
@@ -210,9 +210,6 @@
-
-
-
diff --git a/src/test/java/com/thealgorithms/maths/VolumeTest.java b/src/test/java/com/thealgorithms/maths/VolumeTest.java
index 7cd0c6716147..1ba0aec47cef 100644
--- a/src/test/java/com/thealgorithms/maths/VolumeTest.java
+++ b/src/test/java/com/thealgorithms/maths/VolumeTest.java
@@ -1,6 +1,6 @@
package com.thealgorithms.maths;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
@@ -10,30 +10,30 @@ public class VolumeTest {
public void volume() {
/* test cube */
- assertTrue(Volume.volumeCube(7) == 343.0);
+ assertEquals(Volume.volumeCube(7), 343.0);
/* test cuboid */
- assertTrue(Volume.volumeCuboid(2, 5, 7) == 70.0);
+ assertEquals(Volume.volumeCuboid(2, 5, 7), 70.0);
/* test sphere */
- assertTrue(Volume.volumeSphere(7) == 1436.7550402417319);
+ assertEquals(Volume.volumeSphere(7), 1436.7550402417319);
/* test cylinder */
- assertTrue(Volume.volumeCylinder(3, 7) == 197.92033717615698);
+ assertEquals(Volume.volumeCylinder(3, 7), 197.92033717615698);
/* test hemisphere */
- assertTrue(Volume.volumeHemisphere(7) == 718.3775201208659);
+ assertEquals(Volume.volumeHemisphere(7), 718.3775201208659);
/* test cone */
- assertTrue(Volume.volumeCone(3, 7) == 65.97344572538566);
+ assertEquals(Volume.volumeCone(3, 7), 65.97344572538566);
/* test prism */
- assertTrue(Volume.volumePrism(10, 2) == 20.0);
+ assertEquals(Volume.volumePrism(10, 2), 20.0);
/* test pyramid */
- assertTrue(Volume.volumePyramid(10, 3) == 10.0);
+ assertEquals(Volume.volumePyramid(10, 3), 10.0);
/* test frustum */
- assertTrue(Volume.volumeFrustumOfCone(3, 5, 7) == 359.188760060433);
+ assertEquals(Volume.volumeFrustumOfCone(3, 5, 7), 359.188760060433);
}
}
From a7eeee2b5b20153e47a015ff6e8e8cb66d1424a8 Mon Sep 17 00:00:00 2001
From: Mohammed Vijahath <116938255+vizahat36@users.noreply.github.com>
Date: Thu, 22 Jan 2026 21:39:23 +0530
Subject: [PATCH 12/58] Fix: NumberFormatException with non-ASCII Unicode
digits in MyAtoi (#7231)
Fix myAtoi handling of non-ASCII Unicode digits
---
src/main/java/com/thealgorithms/strings/MyAtoi.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/strings/MyAtoi.java b/src/main/java/com/thealgorithms/strings/MyAtoi.java
index 5a7c2ce53b1c..92de4039a582 100644
--- a/src/main/java/com/thealgorithms/strings/MyAtoi.java
+++ b/src/main/java/com/thealgorithms/strings/MyAtoi.java
@@ -45,7 +45,9 @@ public static int myAtoi(String s) {
int number = 0;
while (index < length) {
char ch = s.charAt(index);
- if (!Character.isDigit(ch)) {
+
+ // Accept only ASCII digits
+ if (ch < '0' || ch > '9') {
break;
}
From 1a7f8fe79e81163cf4f9f6d82270edd6e39d1d82 Mon Sep 17 00:00:00 2001
From: Piotr Idzik <65706193+vil02@users.noreply.github.com>
Date: Fri, 23 Jan 2026 09:39:22 +0100
Subject: [PATCH 13/58] style: include
`UTAO_JUNIT_ASSERTION_ODDITIES_IMPOSSIBLE_NULL` (#7238)
---
spotbugs-exclude.xml | 3 ---
src/test/java/com/thealgorithms/compression/LZ78Test.java | 2 --
2 files changed, 5 deletions(-)
diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml
index c8a7f71cd880..8c51fcf42b2e 100644
--- a/spotbugs-exclude.xml
+++ b/spotbugs-exclude.xml
@@ -216,9 +216,6 @@
-
-
-
diff --git a/src/test/java/com/thealgorithms/compression/LZ78Test.java b/src/test/java/com/thealgorithms/compression/LZ78Test.java
index 7889b50b76f3..da1fd8d23318 100644
--- a/src/test/java/com/thealgorithms/compression/LZ78Test.java
+++ b/src/test/java/com/thealgorithms/compression/LZ78Test.java
@@ -1,7 +1,6 @@
package com.thealgorithms.compression;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
@@ -286,7 +285,6 @@ void testTokenStructure() {
// All tokens should have valid indices (>= 0)
for (LZ78.Token token : compressed) {
assertTrue(token.index() >= 0);
- assertNotNull(token.nextChar());
}
String decompressed = LZ78.decompress(compressed);
From 0b0cefe9f9745ec94ffee3575b98aa953a8c8588 Mon Sep 17 00:00:00 2001
From: Piotr Idzik <65706193+vil02@users.noreply.github.com>
Date: Sat, 24 Jan 2026 14:16:48 +0100
Subject: [PATCH 14/58] style: include
`UTAO_JUNIT_ASSERTION_ODDITIES_ACTUAL_CONSTANT` (#7239)
---
spotbugs-exclude.xml | 3 --
.../backtracking/PermutationTest.java | 4 +-
.../com/thealgorithms/ciphers/ECCTest.java | 2 +-
.../hashmap/hashing/MapTest.java | 6 +--
.../queues/PriorityQueuesTest.java | 28 ++++++-------
.../thealgorithms/io/BufferedReaderTest.java | 40 +++++++++----------
.../maths/DistanceFormulaTest.java | 26 ++++++------
.../thealgorithms/maths/FactorialTest.java | 2 +-
.../maths/NthUglyNumberTest.java | 8 ++--
.../maths/PalindromeNumberTest.java | 2 +-
.../thealgorithms/maths/ParseIntegerTest.java | 4 +-
.../maths/QuadraticEquationSolverTest.java | 20 +++++-----
.../thealgorithms/maths/SecondMinMaxTest.java | 6 +--
.../maths/StandardDeviationTest.java | 8 ++--
.../maths/StandardScoreTest.java | 8 ++--
.../com/thealgorithms/maths/VolumeTest.java | 18 ++++-----
.../misc/MedianOfRunningArrayTest.java | 2 +-
.../searches/BinarySearch2dArrayTest.java | 6 +--
.../thealgorithms/searches/KMPSearchTest.java | 10 ++---
.../searches/QuickSelectTest.java | 2 +-
.../sorts/TopologicalSortTest.java | 2 +-
.../thealgorithms/strings/WordLadderTest.java | 6 +--
.../zigZagPattern/ZigZagPatternTest.java | 4 +-
23 files changed, 107 insertions(+), 110 deletions(-)
diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml
index 8c51fcf42b2e..1390387bacdf 100644
--- a/spotbugs-exclude.xml
+++ b/spotbugs-exclude.xml
@@ -210,9 +210,6 @@
-
-
-
diff --git a/src/test/java/com/thealgorithms/backtracking/PermutationTest.java b/src/test/java/com/thealgorithms/backtracking/PermutationTest.java
index 76a714829109..54747e5e73a1 100644
--- a/src/test/java/com/thealgorithms/backtracking/PermutationTest.java
+++ b/src/test/java/com/thealgorithms/backtracking/PermutationTest.java
@@ -12,13 +12,13 @@ public class PermutationTest {
@Test
void testNoElement() {
List result = Permutation.permutation(new Integer[] {});
- assertEquals(result.get(0).length, 0);
+ assertEquals(0, result.get(0).length);
}
@Test
void testSingleElement() {
List result = Permutation.permutation(new Integer[] {1});
- assertEquals(result.get(0)[0], 1);
+ assertEquals(1, result.get(0)[0]);
}
@Test
diff --git a/src/test/java/com/thealgorithms/ciphers/ECCTest.java b/src/test/java/com/thealgorithms/ciphers/ECCTest.java
index 701f801af1c8..b78ba51f7c3e 100644
--- a/src/test/java/com/thealgorithms/ciphers/ECCTest.java
+++ b/src/test/java/com/thealgorithms/ciphers/ECCTest.java
@@ -37,7 +37,7 @@ void testEncrypt() {
System.out.println("Base Point G: " + curve.getBasePoint());
// Verify that the ciphertext is not empty
- assertEquals(cipherText.length, 2); // Check if the ciphertext contains two points (R and S)
+ assertEquals(2, cipherText.length); // Check if the ciphertext contains two points (R and S)
// Output the encrypted coordinate points
System.out.println("Encrypted Points:");
diff --git a/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/MapTest.java b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/MapTest.java
index 44551a8adac6..ef7739a2e8a9 100644
--- a/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/MapTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/MapTest.java
@@ -81,19 +81,19 @@ void containsTest() {
@Test
void sizeTest() {
Map map = getMap();
- assertEquals(map.size(), 0);
+ assertEquals(0, map.size());
for (int i = -100; i < 100; i++) {
map.put(i, String.valueOf(i));
}
- assertEquals(map.size(), 200);
+ assertEquals(200, map.size());
for (int i = -50; i < 50; i++) {
map.delete(i);
}
- assertEquals(map.size(), 100);
+ assertEquals(100, map.size());
}
@Test
diff --git a/src/test/java/com/thealgorithms/datastructures/queues/PriorityQueuesTest.java b/src/test/java/com/thealgorithms/datastructures/queues/PriorityQueuesTest.java
index e97fe091c556..3bb8bbabb761 100644
--- a/src/test/java/com/thealgorithms/datastructures/queues/PriorityQueuesTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/queues/PriorityQueuesTest.java
@@ -9,14 +9,14 @@ class PriorityQueuesTest {
void testPQInsertion() {
PriorityQueue myQueue = new PriorityQueue(4);
myQueue.insert(2);
- Assertions.assertEquals(myQueue.peek(), 2);
+ Assertions.assertEquals(2, myQueue.peek());
myQueue.insert(5);
myQueue.insert(3);
- Assertions.assertEquals(myQueue.peek(), 5);
+ Assertions.assertEquals(5, myQueue.peek());
myQueue.insert(10);
- Assertions.assertEquals(myQueue.peek(), 10);
+ Assertions.assertEquals(10, myQueue.peek());
}
@Test
@@ -28,32 +28,32 @@ void testPQDeletion() {
myQueue.insert(10);
myQueue.remove();
- Assertions.assertEquals(myQueue.peek(), 5);
+ Assertions.assertEquals(5, myQueue.peek());
myQueue.remove();
myQueue.remove();
- Assertions.assertEquals(myQueue.peek(), 2);
+ Assertions.assertEquals(2, myQueue.peek());
}
@Test
void testPQExtra() {
PriorityQueue myQueue = new PriorityQueue(4);
- Assertions.assertEquals(myQueue.isEmpty(), true);
- Assertions.assertEquals(myQueue.isFull(), false);
+ Assertions.assertTrue(myQueue.isEmpty());
+ Assertions.assertFalse(myQueue.isFull());
myQueue.insert(2);
myQueue.insert(5);
- Assertions.assertEquals(myQueue.isFull(), false);
+ Assertions.assertFalse(myQueue.isFull());
myQueue.insert(3);
myQueue.insert(10);
- Assertions.assertEquals(myQueue.isEmpty(), false);
- Assertions.assertEquals(myQueue.isFull(), true);
+ Assertions.assertFalse(myQueue.isEmpty());
+ Assertions.assertTrue(myQueue.isFull());
myQueue.remove();
- Assertions.assertEquals(myQueue.getSize(), 3);
- Assertions.assertEquals(myQueue.peek(), 5);
+ Assertions.assertEquals(3, myQueue.getSize());
+ Assertions.assertEquals(5, myQueue.peek());
myQueue.remove();
myQueue.remove();
- Assertions.assertEquals(myQueue.peek(), 2);
- Assertions.assertEquals(myQueue.getSize(), 1);
+ Assertions.assertEquals(2, myQueue.peek());
+ Assertions.assertEquals(1, myQueue.getSize());
}
@Test
diff --git a/src/test/java/com/thealgorithms/io/BufferedReaderTest.java b/src/test/java/com/thealgorithms/io/BufferedReaderTest.java
index 891c3066058e..088e86f8f7c5 100644
--- a/src/test/java/com/thealgorithms/io/BufferedReaderTest.java
+++ b/src/test/java/com/thealgorithms/io/BufferedReaderTest.java
@@ -17,15 +17,15 @@ public void testPeeks() throws IOException {
BufferedReader reader = new BufferedReader(input);
// read the first letter
- assertEquals(reader.read(), 'H');
+ assertEquals('H', reader.read());
len--;
- assertEquals(reader.available(), len);
+ assertEquals(len, reader.available());
// position: H[e]llo!\nWorld!
// reader.read() will be == 'e'
- assertEquals(reader.peek(1), 'l');
- assertEquals(reader.peek(2), 'l'); // second l
- assertEquals(reader.peek(3), 'o');
+ assertEquals('l', reader.peek(1));
+ assertEquals('l', reader.peek(2)); // second l
+ assertEquals('o', reader.peek(3));
}
@Test
@@ -38,21 +38,21 @@ public void testMixes() throws IOException {
BufferedReader reader = new BufferedReader(input);
// read the first letter
- assertEquals(reader.read(), 'H'); // first letter
+ assertEquals('H', reader.read()); // first letter
len--;
- assertEquals(reader.peek(1), 'l'); // third later (second letter after 'H')
- assertEquals(reader.read(), 'e'); // second letter
+ assertEquals('l', reader.peek(1)); // third later (second letter after 'H')
+ assertEquals('e', reader.read()); // second letter
len--;
- assertEquals(reader.available(), len);
+ assertEquals(len, reader.available());
// position: H[e]llo!\nWorld!
- assertEquals(reader.peek(2), 'o'); // second l
- assertEquals(reader.peek(3), '!');
- assertEquals(reader.peek(4), '\n');
+ assertEquals('o', reader.peek(2)); // second l
+ assertEquals('!', reader.peek(3));
+ assertEquals('\n', reader.peek(4));
- assertEquals(reader.read(), 'l'); // third letter
- assertEquals(reader.peek(1), 'o'); // fourth letter
+ assertEquals('l', reader.read()); // third letter
+ assertEquals('o', reader.peek(1)); // fourth letter
for (int i = 0; i < 6; i++) {
reader.read();
@@ -74,23 +74,23 @@ public void testBlockPractical() throws IOException {
ByteArrayInputStream input = new ByteArrayInputStream(bytes);
BufferedReader reader = new BufferedReader(input);
- assertEquals(reader.peek(), 'H');
- assertEquals(reader.read(), '!'); // read the first letter
+ assertEquals('H', reader.peek());
+ assertEquals('!', reader.read()); // read the first letter
len--;
// this only reads the next 5 bytes (Hello) because
// the default buffer size = 5
- assertEquals(new String(reader.readBlock()), "Hello");
+ assertEquals("Hello", new String(reader.readBlock()));
len -= 5;
assertEquals(reader.available(), len);
// maybe kind of a practical demonstration / use case
if (reader.read() == '\n') {
- assertEquals(reader.read(), 'W');
- assertEquals(reader.read(), 'o');
+ assertEquals('W', reader.read());
+ assertEquals('o', reader.read());
// the rest of the blocks
- assertEquals(new String(reader.readBlock()), "rld!");
+ assertEquals("rld!", new String(reader.readBlock()));
} else {
// should not reach
throw new IOException("Something not right");
diff --git a/src/test/java/com/thealgorithms/maths/DistanceFormulaTest.java b/src/test/java/com/thealgorithms/maths/DistanceFormulaTest.java
index 3a14b80dd4f9..66f3b7b03938 100644
--- a/src/test/java/com/thealgorithms/maths/DistanceFormulaTest.java
+++ b/src/test/java/com/thealgorithms/maths/DistanceFormulaTest.java
@@ -9,78 +9,78 @@ public class DistanceFormulaTest {
@Test
void euclideanTest1() {
- Assertions.assertEquals(DistanceFormula.euclideanDistance(1, 1, 2, 2), 1.4142135623730951);
+ Assertions.assertEquals(1.4142135623730951, DistanceFormula.euclideanDistance(1, 1, 2, 2));
}
@Test
void euclideanTest2() {
- Assertions.assertEquals(DistanceFormula.euclideanDistance(1, 3, 8, 0), 7.0710678118654755);
+ Assertions.assertEquals(7.0710678118654755, DistanceFormula.euclideanDistance(1, 3, 8, 0));
}
@Test
void euclideanTest3() {
- Assertions.assertEquals(DistanceFormula.euclideanDistance(2.4, 9.1, 55.1, 100), 110.91911467371168);
+ Assertions.assertEquals(110.91911467371168, DistanceFormula.euclideanDistance(2.4, 9.1, 55.1, 100));
}
@Test
void euclideanTest4() {
- Assertions.assertEquals(DistanceFormula.euclideanDistance(1000, 13, 20000, 84), 19022.067605809836);
+ Assertions.assertEquals(19022.067605809836, DistanceFormula.euclideanDistance(1000, 13, 20000, 84));
}
@Test
public void manhattantest1() {
- assertEquals(DistanceFormula.manhattanDistance(1, 2, 3, 4), 4);
+ assertEquals(4, DistanceFormula.manhattanDistance(1, 2, 3, 4));
}
@Test
public void manhattantest2() {
- assertEquals(DistanceFormula.manhattanDistance(6.5, 8.4, 20.1, 13.6), 18.8);
+ assertEquals(18.8, DistanceFormula.manhattanDistance(6.5, 8.4, 20.1, 13.6));
}
@Test
public void manhattanTest3() {
- assertEquals(DistanceFormula.manhattanDistance(10.112, 50, 8, 25.67), 26.442);
+ assertEquals(26.442, DistanceFormula.manhattanDistance(10.112, 50, 8, 25.67));
}
@Test
public void hammingTest1() {
int[] array1 = {1, 1, 1, 1};
int[] array2 = {0, 0, 0, 0};
- assertEquals(DistanceFormula.hammingDistance(array1, array2), 4);
+ assertEquals(4, DistanceFormula.hammingDistance(array1, array2));
}
@Test
public void hammingTest2() {
int[] array1 = {1, 1, 1, 1};
int[] array2 = {1, 1, 1, 1};
- assertEquals(DistanceFormula.hammingDistance(array1, array2), 0);
+ assertEquals(0, DistanceFormula.hammingDistance(array1, array2));
}
@Test
public void hammingTest3() {
int[] array1 = {1, 0, 0, 1, 1, 0, 1, 1, 0};
int[] array2 = {0, 1, 0, 0, 1, 1, 1, 0, 0};
- assertEquals(DistanceFormula.hammingDistance(array1, array2), 5);
+ assertEquals(5, DistanceFormula.hammingDistance(array1, array2));
}
@Test
public void minkowskiTest1() {
double[] array1 = {1, 3, 8, 5};
double[] array2 = {4, 2, 6, 9};
- assertEquals(DistanceFormula.minkowskiDistance(array1, array2, 1), 10);
+ assertEquals(10, DistanceFormula.minkowskiDistance(array1, array2, 1));
}
@Test
public void minkowskiTest2() {
double[] array1 = {1, 3, 8, 5};
double[] array2 = {4, 2, 6, 9};
- assertEquals(DistanceFormula.minkowskiDistance(array1, array2, 2), 5.477225575051661);
+ assertEquals(5.477225575051661, DistanceFormula.minkowskiDistance(array1, array2, 2));
}
@Test
public void minkowskiTest3() {
double[] array1 = {1, 3, 8, 5};
double[] array2 = {4, 2, 6, 9};
- assertEquals(DistanceFormula.minkowskiDistance(array1, array2, 3), 4.641588833612778);
+ assertEquals(4.641588833612778, DistanceFormula.minkowskiDistance(array1, array2, 3));
}
}
diff --git a/src/test/java/com/thealgorithms/maths/FactorialTest.java b/src/test/java/com/thealgorithms/maths/FactorialTest.java
index b38dc45589ee..3ff7097b8113 100644
--- a/src/test/java/com/thealgorithms/maths/FactorialTest.java
+++ b/src/test/java/com/thealgorithms/maths/FactorialTest.java
@@ -11,7 +11,7 @@ public class FactorialTest {
@Test
public void testWhenInvalidInoutProvidedShouldThrowException() {
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> Factorial.factorial(-1));
- assertEquals(exception.getMessage(), EXCEPTION_MESSAGE);
+ assertEquals(EXCEPTION_MESSAGE, exception.getMessage());
}
@Test
diff --git a/src/test/java/com/thealgorithms/maths/NthUglyNumberTest.java b/src/test/java/com/thealgorithms/maths/NthUglyNumberTest.java
index 3fe58dadf8a5..1ee437b190c5 100644
--- a/src/test/java/com/thealgorithms/maths/NthUglyNumberTest.java
+++ b/src/test/java/com/thealgorithms/maths/NthUglyNumberTest.java
@@ -48,22 +48,22 @@ public void testGetWithSameObject() {
var uglyNumbers = new NthUglyNumber(new int[] {7, 2, 5, 3});
for (final var tc : testCases.entrySet()) {
- assertEquals(uglyNumbers.get(tc.getKey()), tc.getValue());
+ assertEquals(tc.getValue(), uglyNumbers.get(tc.getKey()));
}
- assertEquals(uglyNumbers.get(999), 385875);
+ assertEquals(385875, uglyNumbers.get(999));
}
@Test
public void testGetWithBase1() {
var uglyNumbers = new NthUglyNumber(new int[] {1});
- assertEquals(uglyNumbers.get(10), 1);
+ assertEquals(1, uglyNumbers.get(10));
}
@Test
public void testGetWithBase2() {
var uglyNumbers = new NthUglyNumber(new int[] {2});
- assertEquals(uglyNumbers.get(5), 32);
+ assertEquals(32, uglyNumbers.get(5));
}
@Test
diff --git a/src/test/java/com/thealgorithms/maths/PalindromeNumberTest.java b/src/test/java/com/thealgorithms/maths/PalindromeNumberTest.java
index a70100c0b913..4e4bd85d07b5 100644
--- a/src/test/java/com/thealgorithms/maths/PalindromeNumberTest.java
+++ b/src/test/java/com/thealgorithms/maths/PalindromeNumberTest.java
@@ -25,6 +25,6 @@ public void testNumbersAreNotPalindromes() {
@Test
public void testIfNegativeInputThenExceptionExpected() {
IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> PalindromeNumber.isPalindrome(-1));
- Assertions.assertEquals(exception.getMessage(), "Input parameter must not be negative!");
+ Assertions.assertEquals("Input parameter must not be negative!", exception.getMessage());
}
}
diff --git a/src/test/java/com/thealgorithms/maths/ParseIntegerTest.java b/src/test/java/com/thealgorithms/maths/ParseIntegerTest.java
index 7649e21eb231..a9b78be88042 100644
--- a/src/test/java/com/thealgorithms/maths/ParseIntegerTest.java
+++ b/src/test/java/com/thealgorithms/maths/ParseIntegerTest.java
@@ -14,13 +14,13 @@ public class ParseIntegerTest {
@Test
public void testNullInput() {
IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> ParseInteger.parseInt(null));
- Assertions.assertEquals(exception.getMessage(), NULL_PARAMETER_MESSAGE);
+ Assertions.assertEquals(NULL_PARAMETER_MESSAGE, exception.getMessage());
}
@Test
public void testEmptyInput() {
IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> ParseInteger.parseInt(""));
- Assertions.assertEquals(exception.getMessage(), EMPTY_PARAMETER_MESSAGE);
+ Assertions.assertEquals(EMPTY_PARAMETER_MESSAGE, exception.getMessage());
}
@Test
diff --git a/src/test/java/com/thealgorithms/maths/QuadraticEquationSolverTest.java b/src/test/java/com/thealgorithms/maths/QuadraticEquationSolverTest.java
index a2046511ddf5..a6552d56783c 100644
--- a/src/test/java/com/thealgorithms/maths/QuadraticEquationSolverTest.java
+++ b/src/test/java/com/thealgorithms/maths/QuadraticEquationSolverTest.java
@@ -14,10 +14,10 @@ public void testSolveEquationRealRoots() {
double c = 1.9;
ComplexNumber[] roots = quadraticEquationSolver.solveEquation(a, b, c);
- Assertions.assertEquals(roots.length, 2);
- Assertions.assertEquals(roots[0].real, -0.27810465435684306);
+ Assertions.assertEquals(2, roots.length, 2);
+ Assertions.assertEquals(-0.27810465435684306, roots[0].real);
Assertions.assertNull(roots[0].imaginary);
- Assertions.assertEquals(roots[1].real, -1.6266572504050616);
+ Assertions.assertEquals(-1.6266572504050616, roots[1].real);
Assertions.assertNull(roots[1].imaginary);
}
@@ -29,8 +29,8 @@ public void testSolveEquationEqualRoots() {
double c = 1;
ComplexNumber[] roots = quadraticEquationSolver.solveEquation(a, b, c);
- Assertions.assertEquals(roots.length, 1);
- Assertions.assertEquals(roots[0].real, -1);
+ Assertions.assertEquals(1, roots.length);
+ Assertions.assertEquals(-1, roots[0].real);
}
@Test
@@ -41,10 +41,10 @@ public void testSolveEquationComplexRoots() {
double c = 5.6;
ComplexNumber[] roots = quadraticEquationSolver.solveEquation(a, b, c);
- Assertions.assertEquals(roots.length, 2);
- Assertions.assertEquals(roots[0].real, -0.8695652173913044);
- Assertions.assertEquals(roots[0].imaginary, 1.2956229935435948);
- Assertions.assertEquals(roots[1].real, -0.8695652173913044);
- Assertions.assertEquals(roots[1].imaginary, -1.2956229935435948);
+ Assertions.assertEquals(2, roots.length);
+ Assertions.assertEquals(-0.8695652173913044, roots[0].real);
+ Assertions.assertEquals(1.2956229935435948, roots[0].imaginary);
+ Assertions.assertEquals(-0.8695652173913044, roots[1].real);
+ Assertions.assertEquals(-1.2956229935435948, roots[1].imaginary);
}
}
diff --git a/src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java b/src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java
index c744614e5cfa..c5d47f2213a9 100644
--- a/src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java
+++ b/src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java
@@ -29,19 +29,19 @@ public TestCase(final int[] inInputArray, final int inSecondMin, final int inSec
@Test
public void testForEmptyInputArray() {
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> SecondMinMax.findSecondMin(new int[] {}));
- assertEquals(exception.getMessage(), EXP_MSG_ARR_LEN_LESS_2);
+ assertEquals(EXP_MSG_ARR_LEN_LESS_2, exception.getMessage());
}
@Test
public void testForArrayWithSingleElement() {
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> SecondMinMax.findSecondMax(new int[] {1}));
- assertEquals(exception.getMessage(), EXP_MSG_ARR_LEN_LESS_2);
+ assertEquals(EXP_MSG_ARR_LEN_LESS_2, exception.getMessage());
}
@Test
public void testForArrayWithSameElements() {
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> SecondMinMax.findSecondMin(new int[] {1, 1, 1, 1}));
- assertEquals(exception.getMessage(), EXP_MSG_ARR_SAME_ELE);
+ assertEquals(EXP_MSG_ARR_SAME_ELE, exception.getMessage());
}
@ParameterizedTest
diff --git a/src/test/java/com/thealgorithms/maths/StandardDeviationTest.java b/src/test/java/com/thealgorithms/maths/StandardDeviationTest.java
index 2c10d2d14f3e..4716d389a4ca 100644
--- a/src/test/java/com/thealgorithms/maths/StandardDeviationTest.java
+++ b/src/test/java/com/thealgorithms/maths/StandardDeviationTest.java
@@ -8,19 +8,19 @@ public class StandardDeviationTest {
@Test
void test1() {
double[] t1 = new double[] {1, 1, 1, 1, 1};
- Assertions.assertEquals(StandardDeviation.stdDev(t1), 0.0);
+ Assertions.assertEquals(0.0, StandardDeviation.stdDev(t1));
}
@Test
void test2() {
double[] t2 = new double[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
- Assertions.assertEquals(StandardDeviation.stdDev(t2), 2.8722813232690143);
+ Assertions.assertEquals(2.8722813232690143, StandardDeviation.stdDev(t2));
}
@Test
void test3() {
double[] t3 = new double[] {1.1, 8.5, 20.3, 2.4, 6.2};
- Assertions.assertEquals(StandardDeviation.stdDev(t3), 6.8308125431752265);
+ Assertions.assertEquals(6.8308125431752265, StandardDeviation.stdDev(t3));
}
@Test
@@ -32,6 +32,6 @@ void test4() {
100.00045,
56.7,
};
- Assertions.assertEquals(StandardDeviation.stdDev(t4), 38.506117353865775);
+ Assertions.assertEquals(38.506117353865775, StandardDeviation.stdDev(t4));
}
}
diff --git a/src/test/java/com/thealgorithms/maths/StandardScoreTest.java b/src/test/java/com/thealgorithms/maths/StandardScoreTest.java
index 436b1fd011c6..6858b87ad2c6 100644
--- a/src/test/java/com/thealgorithms/maths/StandardScoreTest.java
+++ b/src/test/java/com/thealgorithms/maths/StandardScoreTest.java
@@ -7,21 +7,21 @@ public class StandardScoreTest {
@Test
void test1() {
- Assertions.assertEquals(StandardScore.zScore(2, 0, 5), 0.4);
+ Assertions.assertEquals(0.4, StandardScore.zScore(2, 0, 5));
}
@Test
void test2() {
- Assertions.assertEquals(StandardScore.zScore(1, 1, 1), 0.0);
+ Assertions.assertEquals(0.0, StandardScore.zScore(1, 1, 1));
}
@Test
void test3() {
- Assertions.assertEquals(StandardScore.zScore(2.5, 1.8, 0.7), 1.0);
+ Assertions.assertEquals(1.0, StandardScore.zScore(2.5, 1.8, 0.7));
}
@Test
void test4() {
- Assertions.assertEquals(StandardScore.zScore(8.9, 3, 4.2), 1.4047619047619049);
+ Assertions.assertEquals(1.4047619047619049, StandardScore.zScore(8.9, 3, 4.2));
}
}
diff --git a/src/test/java/com/thealgorithms/maths/VolumeTest.java b/src/test/java/com/thealgorithms/maths/VolumeTest.java
index 1ba0aec47cef..af882eef7563 100644
--- a/src/test/java/com/thealgorithms/maths/VolumeTest.java
+++ b/src/test/java/com/thealgorithms/maths/VolumeTest.java
@@ -10,30 +10,30 @@ public class VolumeTest {
public void volume() {
/* test cube */
- assertEquals(Volume.volumeCube(7), 343.0);
+ assertEquals(343.0, Volume.volumeCube(7));
/* test cuboid */
- assertEquals(Volume.volumeCuboid(2, 5, 7), 70.0);
+ assertEquals(70.0, Volume.volumeCuboid(2, 5, 7));
/* test sphere */
- assertEquals(Volume.volumeSphere(7), 1436.7550402417319);
+ assertEquals(1436.7550402417319, Volume.volumeSphere(7));
/* test cylinder */
- assertEquals(Volume.volumeCylinder(3, 7), 197.92033717615698);
+ assertEquals(197.92033717615698, Volume.volumeCylinder(3, 7));
/* test hemisphere */
- assertEquals(Volume.volumeHemisphere(7), 718.3775201208659);
+ assertEquals(718.3775201208659, Volume.volumeHemisphere(7));
/* test cone */
- assertEquals(Volume.volumeCone(3, 7), 65.97344572538566);
+ assertEquals(65.97344572538566, Volume.volumeCone(3, 7));
/* test prism */
- assertEquals(Volume.volumePrism(10, 2), 20.0);
+ assertEquals(20.0, Volume.volumePrism(10, 2));
/* test pyramid */
- assertEquals(Volume.volumePyramid(10, 3), 10.0);
+ assertEquals(10.0, Volume.volumePyramid(10, 3));
/* test frustum */
- assertEquals(Volume.volumeFrustumOfCone(3, 5, 7), 359.188760060433);
+ assertEquals(359.188760060433, Volume.volumeFrustumOfCone(3, 5, 7));
}
}
diff --git a/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java b/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java
index f41953035846..c4a74af0ba8b 100644
--- a/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java
+++ b/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java
@@ -17,7 +17,7 @@ public class MedianOfRunningArrayTest {
public void testWhenInvalidInoutProvidedShouldThrowException() {
var stream = new MedianOfRunningArrayInteger();
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, stream::getMedian);
- assertEquals(exception.getMessage(), EXCEPTION_MESSAGE);
+ assertEquals(EXCEPTION_MESSAGE, exception.getMessage());
}
@Test
diff --git a/src/test/java/com/thealgorithms/searches/BinarySearch2dArrayTest.java b/src/test/java/com/thealgorithms/searches/BinarySearch2dArrayTest.java
index 18f0afc6a0a6..dec2c86de9c7 100644
--- a/src/test/java/com/thealgorithms/searches/BinarySearch2dArrayTest.java
+++ b/src/test/java/com/thealgorithms/searches/BinarySearch2dArrayTest.java
@@ -117,7 +117,7 @@ public void binarySearch2dArrayTestTargetInMiddle() {
int target = 8;
// Assert that the requirement, that the target is in the middle row and middle column, is
// fulfilled.
- assertEquals(arr[arr.length / 2][arr[0].length / 2], target);
+ assertEquals(target, arr[arr.length / 2][arr[0].length / 2]);
int[] ans = BinarySearch2dArray.binarySearch(arr, target);
System.out.println(Arrays.toString(ans));
assertEquals(1, ans[0]);
@@ -135,8 +135,8 @@ public void binarySearch2dArrayTestTargetAboveMiddleRowInMiddleColumn() {
// Assert that the requirement, that he target is in the middle column,
// in an array with an even number of columns, and on the row "above" the middle row.
- assertEquals(arr[0].length % 2, 0);
- assertEquals(arr[arr.length / 2 - 1][arr[0].length / 2], target);
+ assertEquals(0, arr[0].length % 2);
+ assertEquals(target, arr[arr.length / 2 - 1][arr[0].length / 2]);
int[] ans = BinarySearch2dArray.binarySearch(arr, target);
System.out.println(Arrays.toString(ans));
assertEquals(0, ans[0]);
diff --git a/src/test/java/com/thealgorithms/searches/KMPSearchTest.java b/src/test/java/com/thealgorithms/searches/KMPSearchTest.java
index cb804ac6a6a3..216c5fcd7d2c 100644
--- a/src/test/java/com/thealgorithms/searches/KMPSearchTest.java
+++ b/src/test/java/com/thealgorithms/searches/KMPSearchTest.java
@@ -14,7 +14,7 @@ public void kmpSearchTestLast() {
KMPSearch kmpSearch = new KMPSearch();
int value = kmpSearch.kmpSearch(pat, txt);
System.out.println(value);
- assertEquals(value, 10);
+ assertEquals(10, value);
}
@Test
@@ -25,7 +25,7 @@ public void kmpSearchTestFront() {
KMPSearch kmpSearch = new KMPSearch();
int value = kmpSearch.kmpSearch(pat, txt);
System.out.println(value);
- assertEquals(value, 0);
+ assertEquals(0, value);
}
@Test
@@ -36,7 +36,7 @@ public void kmpSearchTestMiddle() {
KMPSearch kmpSearch = new KMPSearch();
int value = kmpSearch.kmpSearch(pat, txt);
System.out.println(value);
- assertEquals(value, 4);
+ assertEquals(4, value);
}
@Test
@@ -47,7 +47,7 @@ public void kmpSearchTestNotFound() {
KMPSearch kmpSearch = new KMPSearch();
int value = kmpSearch.kmpSearch(pat, txt);
System.out.println(value);
- assertEquals(value, 4);
+ assertEquals(4, value);
}
@Test
@@ -58,6 +58,6 @@ public void kmpSearchTest4() {
KMPSearch kmpSearch = new KMPSearch();
int value = kmpSearch.kmpSearch(pat, txt);
System.out.println(value);
- assertEquals(value, -1);
+ assertEquals(-1, value);
}
}
diff --git a/src/test/java/com/thealgorithms/searches/QuickSelectTest.java b/src/test/java/com/thealgorithms/searches/QuickSelectTest.java
index cf160b0ff4b5..4c96be76861a 100644
--- a/src/test/java/com/thealgorithms/searches/QuickSelectTest.java
+++ b/src/test/java/com/thealgorithms/searches/QuickSelectTest.java
@@ -172,7 +172,7 @@ void quickSelect70thPercentileOfManyElements() {
void quickSelectMedianOfThreeCharacters() {
List elements = Arrays.asList('X', 'Z', 'Y');
char actual = QuickSelect.select(elements, 1);
- assertEquals(actual, 'Y');
+ assertEquals('Y', actual);
}
@Test
diff --git a/src/test/java/com/thealgorithms/sorts/TopologicalSortTest.java b/src/test/java/com/thealgorithms/sorts/TopologicalSortTest.java
index d5588b2b968e..e19f5b928263 100644
--- a/src/test/java/com/thealgorithms/sorts/TopologicalSortTest.java
+++ b/src/test/java/com/thealgorithms/sorts/TopologicalSortTest.java
@@ -58,7 +58,7 @@ public void failureTest() {
Exception exception = assertThrows(RuntimeException.class, () -> TopologicalSort.sort(graph));
String expected = "This graph contains a cycle. No linear ordering is possible. "
+ "Back edge: 6 -> 2";
- assertEquals(exception.getMessage(), expected);
+ assertEquals(expected, exception.getMessage());
}
@Test
void testEmptyGraph() {
diff --git a/src/test/java/com/thealgorithms/strings/WordLadderTest.java b/src/test/java/com/thealgorithms/strings/WordLadderTest.java
index 221953411da7..c029940abfb0 100644
--- a/src/test/java/com/thealgorithms/strings/WordLadderTest.java
+++ b/src/test/java/com/thealgorithms/strings/WordLadderTest.java
@@ -24,7 +24,7 @@ public class WordLadderTest {
public void testWordLadder() {
List wordList1 = Arrays.asList("hot", "dot", "dog", "lot", "log", "cog");
- assertEquals(WordLadder.ladderLength("hit", "cog", wordList1), 5);
+ assertEquals(5, WordLadder.ladderLength("hit", "cog", wordList1));
}
/**
@@ -39,7 +39,7 @@ public void testWordLadder() {
public void testWordLadder2() {
List wordList2 = Arrays.asList("hot", "dot", "dog", "lot", "log");
- assertEquals(WordLadder.ladderLength("hit", "cog", wordList2), 0);
+ assertEquals(0, WordLadder.ladderLength("hit", "cog", wordList2));
}
/**
@@ -54,7 +54,7 @@ public void testWordLadder2() {
public void testWordLadder3() {
List wordList3 = emptyList();
- assertEquals(WordLadder.ladderLength("hit", "cog", wordList3), 0);
+ assertEquals(0, WordLadder.ladderLength("hit", "cog", wordList3));
}
@ParameterizedTest
diff --git a/src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java b/src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java
index 2cbbfe3d2dd8..9bf118c9b844 100644
--- a/src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java
+++ b/src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java
@@ -9,8 +9,8 @@ public class ZigZagPatternTest {
public void testZigZagPattern() {
String input1 = "HelloWorldFromJava";
String input2 = "javaIsAProgrammingLanguage";
- Assertions.assertEquals(ZigZagPattern.encode(input1, 4), "HooeWrrmalolFJvlda");
- Assertions.assertEquals(ZigZagPattern.encode(input2, 4), "jAaLgasPrmgaaevIrgmnnuaoig");
+ Assertions.assertEquals("HooeWrrmalolFJvlda", ZigZagPattern.encode(input1, 4));
+ Assertions.assertEquals("jAaLgasPrmgaaevIrgmnnuaoig", ZigZagPattern.encode(input2, 4));
// Edge cases
Assertions.assertEquals("ABC", ZigZagPattern.encode("ABC", 1)); // Single row
Assertions.assertEquals("A", ZigZagPattern.encode("A", 2)); // numRows > length of string
From 6fdf2db2989b2cea5ecbf27953f24ff6ac461f82 Mon Sep 17 00:00:00 2001
From: Piotr Idzik <65706193+vil02@users.noreply.github.com>
Date: Sun, 25 Jan 2026 12:44:41 +0100
Subject: [PATCH 15/58] style: resolve some of the
`UTAO_JUNIT_ASSERTION_ODDITIES_USE_ASSERT_EQUALS` warnings (#7240)
---
.../com/thealgorithms/backtracking/CombinationTest.java | 8 ++++----
.../java/com/thealgorithms/misc/ShuffleArrayTest.java | 3 ++-
.../java/com/thealgorithms/others/PasswordGenTest.java | 2 +-
3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/src/test/java/com/thealgorithms/backtracking/CombinationTest.java b/src/test/java/com/thealgorithms/backtracking/CombinationTest.java
index a9d1163f3ecd..5d2f99ccadf8 100644
--- a/src/test/java/com/thealgorithms/backtracking/CombinationTest.java
+++ b/src/test/java/com/thealgorithms/backtracking/CombinationTest.java
@@ -28,16 +28,16 @@ void testNoElement() {
@Test
void testLengthOne() {
List> result = Combination.combination(new Integer[] {1, 2}, 1);
- assertTrue(result.get(0).iterator().next() == 1);
- assertTrue(result.get(1).iterator().next() == 2);
+ assertEquals(1, result.get(0).iterator().next());
+ assertEquals(2, result.get(1).iterator().next());
}
@Test
void testLengthTwo() {
List> result = Combination.combination(new Integer[] {1, 2}, 2);
Integer[] arr = result.get(0).toArray(new Integer[2]);
- assertTrue(arr[0] == 1);
- assertTrue(arr[1] == 2);
+ assertEquals(1, arr[0]);
+ assertEquals(2, arr[1]);
}
@Test
diff --git a/src/test/java/com/thealgorithms/misc/ShuffleArrayTest.java b/src/test/java/com/thealgorithms/misc/ShuffleArrayTest.java
index 915b83e376b6..c1adafa18d9f 100644
--- a/src/test/java/com/thealgorithms/misc/ShuffleArrayTest.java
+++ b/src/test/java/com/thealgorithms/misc/ShuffleArrayTest.java
@@ -1,6 +1,7 @@
package com.thealgorithms.misc;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -67,7 +68,7 @@ void testShuffleRetainsElements() {
ShuffleArray.shuffle(arr);
// Check that the shuffled array contains the same elements
- assertTrue(arr.length == 5);
+ assertEquals(5, arr.length);
for (int i = 1; i <= 5; i++) {
assertTrue(contains(arr, i));
}
diff --git a/src/test/java/com/thealgorithms/others/PasswordGenTest.java b/src/test/java/com/thealgorithms/others/PasswordGenTest.java
index 76492556e75f..4dcdf6b9cf4f 100644
--- a/src/test/java/com/thealgorithms/others/PasswordGenTest.java
+++ b/src/test/java/com/thealgorithms/others/PasswordGenTest.java
@@ -17,7 +17,7 @@ public void failGenerationWithSameMinMaxLengthTest() {
@Test
public void generateOneCharacterPassword() {
String tempPassword = PasswordGen.generatePassword(1, 2);
- assertTrue(tempPassword.length() == 1);
+ assertEquals(1, tempPassword.length());
}
@Test
From a3efc108b8970adfe71baef44510b1f5552ca342 Mon Sep 17 00:00:00 2001
From: Deniz Altunkapan
Date: Mon, 26 Jan 2026 22:33:04 +0100
Subject: [PATCH 16/58] Docs/remove readme korean readme file (#7242)
* fix: prevent duplicate auth header in GitHub Actions workflow
* chore: remove Korean README file
---
.github/workflows/update-directorymd.yml | 2 +-
README-ko.md | 191 -----------------------
2 files changed, 1 insertion(+), 192 deletions(-)
delete mode 100644 README-ko.md
diff --git a/.github/workflows/update-directorymd.yml b/.github/workflows/update-directorymd.yml
index aa553b46a23b..1cfee6e36e4e 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:
diff --git a/README-ko.md b/README-ko.md
deleted file mode 100644
index 4f8cab92fc42..000000000000
--- a/README-ko.md
+++ /dev/null
@@ -1,191 +0,0 @@
-# 알고리즘 - 자바
-
-## 이 [개발브런치](https://github.com/TheAlgorithms/Java/tree/Development)는 기존 프로젝트를 Java 프로젝트 구조로 재개발하기 위해 작성되었다. 기여도를 위해 개발 지사로 전환할 수 있다. 자세한 내용은 이 문제를 참조하십시오. 컨트리뷰션을 위해 [개발브런치](https://github.com/TheAlgorithms/Java/tree/Development)로 전환할 수 있다. 자세한 내용은 [이 이슈](https://github.com/TheAlgorithms/Java/issues/474)를 참고하십시오.
-
-### 자바로 구현된 모든 알고리즘들 (교육용)
-
-이것들은 단지 시범을 위한 것이다. 표준 자바 라이브러리에는 성능상의 이유로 더 나은 것들이 구현되어있다
-
-## 정렬 알고리즘
-
-### Bubble(버블 정렬)
-
-![alt text][bubble-image]
-
-From [Wikipedia][bubble-wiki]: 버블 소트(sinking sor라고도 불리움)는 리스트를 반복적인 단계로 접근하여 정렬한다. 각각의 짝을 비교하며, 순서가 잘못된 경우 그접한 아이템들을 스왑하는 알고리즘이다. 더 이상 스왑할 것이 없을 때까지 반복하며, 반복이 끝남음 리스트가 정렬되었음을 의미한다.
-
-**속성**
-
-- 최악의 성능 O(n^2)
-- 최고의 성능 O(n)
-- 평균 성능 O(n^2)
-
-###### View the algorithm in [action][bubble-toptal]
-
-### Insertion(삽입 정렬)
-
-![alt text][insertion-image]
-
-From [Wikipedia][insertion-wiki]: 삽입 정렬은 최종 정렬된 배열(또는 리스트)을 한번에 하나씩 구축하는 알고리즘이다. 이것은 큰 리스트에서 더 나은 알고리즘인 퀵 소트, 힙 소트, 또는 머지 소트보다 훨씬 안좋은 효율을 가진다. 그림에서 각 막대는 정렬해야 하는 배열의 요소를 나타낸다. 상단과 두 번째 상단 막대의 첫 번째 교차점에서 발생하는 것은 두 번째 요소가 첫 번째 요소보다 더 높은 우선 순위를 가지기 때문에 막대로 표시되는 이러한 요소를 교환한 것이다. 이 방법을 반복하면 삽입 정렬이 완료된다.
-
-**속성**
-
-- 최악의 성능 O(n^2)
-- 최고의 성능 O(n)
-- 평균 O(n^2)
-
-###### View the algorithm in [action][insertion-toptal]
-
-### Merge(합병 정렬)
-
-![alt text][merge-image]
-
-From [Wikipedia][merge-wiki]: 컴퓨터 과학에서, 합병 정렬은 효율적인, 범용적인, 비교 기반 정렬 알고리즘이다. 대부분의 구현은 안정적인 분류를 이루는데, 이것은 구현이 정렬된 출력에 동일한 요소의 입력 순서를 유지한다는 것을 의미한다. 합병 정렬은 1945년에 John von Neumann이 발명한 분할 정복 알고리즘이다.
-
-**속성**
-
-- 최악의 성능 O(n log n) (일반적)
-- 최고의 성능 O(n log n)
-- 평균 O(n log n)
-
-###### View the algorithm in [action][merge-toptal]
-
-### Quick(퀵 정렬)
-
-![alt text][quick-image]
-
-From [Wikipedia][quick-wiki]: 퀵 정렬sometimes called partition-exchange sort)은 효율적인 정렬 알고리즘으로, 배열의 요소를 순서대로 정렬하는 체계적인 방법 역활을 한다.
-
-**속성**
-
-- 최악의 성능 O(n^2)
-- 최고의 성능 O(n log n) or O(n) with three-way partition
-- 평균 O(n log n)
-
-###### View the algorithm in [action][quick-toptal]
-
-### Selection(선택 정렬)
-
-![alt text][selection-image]
-
-From [Wikipedia][selection-wiki]: 알고리즘 입력 리스트를 두 부분으로 나눈다 : 첫 부분은 아이템들이 이미 왼쪽에서 오른쪽으로 정렬되었다. 그리고 남은 부분의 아이템들은 나머지 항목을 차지하는 리스트이다. 처음에는 정렬된 리스트는 공백이고 나머지가 전부이다. 오르차순(또는 내림차순) 알고리즘은 가장 작은 요소를 정렬되지 않은 리스트에서 찾고 정렬이 안된 가장 왼쪽(정렬된 리스트) 리스트와 바꾼다. 이렇게 오른쪽으로 나아간다.
-
-**속성**
-
-- 최악의 성능 O(n^2)
-- 최고의 성능 O(n^2)
-- 평균 O(n^2)
-
-###### View the algorithm in [action][selection-toptal]
-
-### Shell(쉘 정렬)
-
-![alt text][shell-image]
-
-From [Wikipedia][shell-wiki]: 쉘 정렬은 멀리 떨어져 있는 항목의 교환을 허용하는 삽입 종류의 일반화이다. 그 아이디어는 모든 n번째 요소가 정렬된 목록을 제공한다는 것을 고려하여 어느 곳에서든지 시작하도록 요소의 목록을 배열하는 것이다. 이러한 목록은 h-sorted로 알려져 있다. 마찬가지로, 각각 개별적으로 정렬된 h 인터리브 목록으로 간주할 수 있다.
-
-**속성**
-
-- 최악의 성능 O(nlog2 2n)
-- 최고의 성능 O(n log n)
-- Average case performance depends on gap sequence
-
-###### View the algorithm in [action][shell-toptal]
-
-### 시간 복잡성 그래프
-
-정렬 알고리즘의 복잡성 비교 (버블 정렬, 삽입 정렬, 선택 정렬)
-
-[복잡성 그래프](https://github.com/prateekiiest/Python/blob/master/sorts/sortinggraphs.png)
-
----
-
-## 검색 알고리즘
-
-### Linear (선형 탐색)
-
-![alt text][linear-image]
-
-From [Wikipedia][linear-wiki]: 선형 탐색 또는 순차 탐색은 목록 내에서 목표값을 찾는 방법이다. 일치 항목이 발견되거나 모든 요소가 탐색될 때까지 목록의 각 요소에 대해 목표값을 순차적으로 검사한다.
-선형 검색은 최악의 선형 시간으로 실행되며 최대 n개의 비교에서 이루어진다. 여기서 n은 목록의 길이다.
-
-**속성**
-
-- 최악의 성능 O(n)
-- 최고의 성능 O(1)
-- 평균 O(n)
-- 최악의 경우 공간 복잡성 O(1) iterative
-
-### Binary (이진 탐색)
-
-![alt text][binary-image]
-
-From [Wikipedia][binary-wiki]: 이진 탐색, (also known as half-interval search or logarithmic search), 은 정렬된 배열 내에서 목표값의 위치를 찾는 검색 알고리즘이다. 목표값을 배열의 중간 요소와 비교한다; 만약 목표값이 동일하지 않으면, 목표물의 절반이 제거되고 검색이 성공할 때까지 나머지 절반에서 속된다.
-
-**속성**
-
-- 최악의 성능 O(log n)
-- 최고의 성능 O(1)
-- 평균 O(log n)
-- 최악의 경우 공간 복잡성 O(1)
-
-[bubble-toptal]: https://www.toptal.com/developers/sorting-algorithms/bubble-sort
-[bubble-wiki]: https://en.wikipedia.org/wiki/Bubble_sort
-[bubble-image]: https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/Bubblesort-edited-color.svg/220px-Bubblesort-edited-color.svg.png "Bubble Sort"
-[insertion-toptal]: https://www.toptal.com/developers/sorting-algorithms/insertion-sort
-[insertion-wiki]: https://en.wikipedia.org/wiki/Insertion_sort
-[insertion-image]: https://upload.wikimedia.org/wikipedia/commons/7/7e/Insertionsort-edited.png "Insertion Sort"
-[quick-toptal]: https://www.toptal.com/developers/sorting-algorithms/quick-sort
-[quick-wiki]: https://en.wikipedia.org/wiki/Quicksort
-[quick-image]: https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif "Quick Sort"
-[merge-toptal]: https://www.toptal.com/developers/sorting-algorithms/merge-sort
-[merge-wiki]: https://en.wikipedia.org/wiki/Merge_sort
-[merge-image]: https://upload.wikimedia.org/wikipedia/commons/c/cc/Merge-sort-example-300px.gif "Merge Sort"
-[selection-toptal]: https://www.toptal.com/developers/sorting-algorithms/selection-sort
-[selection-wiki]: https://en.wikipedia.org/wiki/Selection_sort
-[selection-image]: https://upload.wikimedia.org/wikipedia/commons/thumb/b/b0/Selection_sort_animation.gif/250px-Selection_sort_animation.gif "Selection Sort Sort"
-[shell-toptal]: https://www.toptal.com/developers/sorting-algorithms/shell-sort
-[shell-wiki]: https://en.wikipedia.org/wiki/Shellsort
-[shell-image]: https://upload.wikimedia.org/wikipedia/commons/d/d8/Sorting_shellsort_anim.gif "Shell Sort"
-[linear-wiki]: https://en.wikipedia.org/wiki/Linear_search
-[linear-image]: http://www.tutorialspoint.com/data_structures_algorithms/images/linear_search.gif
-[binary-wiki]: https://en.wikipedia.org/wiki/Binary_search_algorithm
-[binary-image]: https://upload.wikimedia.org/wikipedia/commons/f/f7/Binary_search_into_array.png
-
----
-
-## 나머지 알고리즘에 대한 링크
-
-| 전환 | 다이나믹프로그래밍(DP) | 암호 | 그 외 것들 |
-| --------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------ |
-| [Any Base to Any Base](Conversions/AnyBaseToAnyBase.java) | [Coin Change](DynamicProgramming/CoinChange.java) | [Caesar](Ciphers/Caesar.java) | [Heap Sort](Sorts/HeapSort.java) |
-| [Any Base to Decimal](Conversions/AnyBaseToDecimal.java) | [Egg Dropping](DynamicProgramming/EggDropping.java) | [Columnar Transposition Cipher](Ciphers/ColumnarTranspositionCipher.java) | [Palindromic Prime Checker](Misc/PalindromePrime.java) |
-| [Binary to Decimal](Conversions/BinaryToDecimal.java) | [Fibonacci](DynamicProgramming/Fibonacci.java) | [RSA](Ciphers/RSA.java) | More soon... |
-| [Binary to HexaDecimal](Conversions/BinaryToHexadecimal.java) | [Kadane Algorithm](DynamicProgramming/KadaneAlgorithm.java) | more coming soon... |
-| [Binary to Octal](Conversions/BinaryToOctal.java) | [Knapsack](DynamicProgramming/Knapsack.java) |
-| [Decimal To Any Base](Conversions/DecimalToAnyBase.java) | [Longest Common Subsequence](DynamicProgramming/LongestCommonSubsequence.java) |
-| [Decimal To Binary](Conversions/DecimalToBinary.java) | [Longest Increasing Subsequence](DynamicProgramming/LongestIncreasingSubsequence.java) |
-| [Decimal To Hexadecimal](Conversions/DecimalToHexaDecimal.java) | [Rod Cutting](DynamicProgramming/RodCutting.java) |
-| and much more... | and more... |
-
-### 자료 구조
-
-| 그래프 | 힙 | 리스트 | 큐 |
-| ------------------------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------- | --------------------------------------------------------------------------- |
-| | [빈 힙 예외처리](DataStructures/Heaps/EmptyHeapException.java) | [원형 연결리스트](DataStructures/Lists/CircleLinkedList.java) | [제너릭 어레이 리스트 큐](DataStructures/Queues/GenericArrayListQueue.java) |
-| | [힙](DataStructures/Heaps/Heap.java) | [이중 연결리스트](DataStructures/Lists/DoublyLinkedList.java) | [큐](DataStructures/Queues/Queues.java) |
-| [그래프](DataStructures/Graphs/Graphs.java) | [힙 요소](DataStructures/Heaps/HeapElement.java) | [단순 연결리스트](DataStructures/Lists/SinglyLinkedList.java) |
-| [크루스칼 알고리즘](DataStructures/Graphs/Kruskal.java) | [최대힙](DataStructures/Heaps/MaxHeap.java) |
-| [행렬 그래프](DataStructures/Graphs/MatrixGraphs.java) | [최소힙](DataStructures/Heaps/MinHeap.java) |
-| [프림 최소신장트리](DataStructures/Graphs/PrimMST.java) |
-
-| 스택 | 트리 |
-| --------------------------------------------------------------- | ------------------------------------------------- |
-| [노드 스택](DataStructures/Stacks/NodeStack.java) | [AVL 트리](DataStructures/Trees/AVLTree.java) |
-| [연결리스트 스택](DataStructures/Stacks/StackOfLinkedList.java) | [이진 트리](DataStructures/Trees/BinaryTree.java) |
-| [스택](DataStructures/Stacks) | And much more... |
-
-- [Bags](DataStructures/Bags/Bag.java)
-- [Buffer](DataStructures/Buffers/CircularBuffer.java)
-- [HashMap](DataStructures/HashMap/Hashing/HashMap.java)
--
From 2ea3873b9ff15d64d6160715365aae7e6590958a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 27 Jan 2026 00:46:45 +0100
Subject: [PATCH 17/58] chore(deps-dev): bump org.assertj:assertj-core from
3.27.6 to 3.27.7 (#7243)
Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.27.6 to 3.27.7.
- [Release notes](https://github.com/assertj/assertj/releases)
- [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.27.6...assertj-build-3.27.7)
---
updated-dependencies:
- dependency-name: org.assertj:assertj-core
dependency-version: 3.27.7
dependency-type: direct:development
...
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 3f81e66d35c0..170e3900b77f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,7 @@
UTF-8
21
21
- 3.27.6
+ 3.27.7
From dc3d64f51d59268e9de8f2334a0327fb0bcbb957 Mon Sep 17 00:00:00 2001
From: Chahat Sandhu
Date: Tue, 27 Jan 2026 15:29:05 -0600
Subject: [PATCH 18/58] feat: add Difference Array algorithm implementation and
tests (#7244)
---
.../prefixsum/DifferenceArray.java | 87 ++++++++++++++
.../prefixsum/DifferenceArrayTest.java | 110 ++++++++++++++++++
2 files changed, 197 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/prefixsum/DifferenceArray.java
create mode 100644 src/test/java/com/thealgorithms/prefixsum/DifferenceArrayTest.java
diff --git a/src/main/java/com/thealgorithms/prefixsum/DifferenceArray.java b/src/main/java/com/thealgorithms/prefixsum/DifferenceArray.java
new file mode 100644
index 000000000000..1be55039cff0
--- /dev/null
+++ b/src/main/java/com/thealgorithms/prefixsum/DifferenceArray.java
@@ -0,0 +1,87 @@
+package com.thealgorithms.prefixsum;
+
+/**
+ * Implements the Difference Array algorithm.
+ *
+ *
+ * The Difference Array is an auxiliary data structure that enables efficient range update operations.
+ * It is based on the mathematical concept of Finite Differences.
+ *
+ *
+ *
+ * Key Operations:
+ *
+ * - Range Update (Add value to [L, R]): O(1)
+ * - Reconstruction (Prefix Sum): O(N)
+ *
+ *
+ *
+ * @see Finite Difference (Wikipedia)
+ * @see Prefix Sum (Wikipedia)
+ * @author Chahat Sandhu, singhc7
+ */
+public class DifferenceArray {
+
+ private final long[] differenceArray;
+ private final int n;
+
+ /**
+ * Initializes the Difference Array from a given integer array.
+ *
+ * @param inputArray The initial array. Cannot be null or empty.
+ * @throws IllegalArgumentException if the input array is null or empty.
+ */
+ public DifferenceArray(int[] inputArray) {
+ if (inputArray == null || inputArray.length == 0) {
+ throw new IllegalArgumentException("Input array cannot be null or empty.");
+ }
+ this.n = inputArray.length;
+ // Size n + 1 allows for branchless updates at the right boundary (r + 1).
+ this.differenceArray = new long[n + 1];
+ initializeDifferenceArray(inputArray);
+ }
+
+ private void initializeDifferenceArray(int[] inputArray) {
+ differenceArray[0] = inputArray[0];
+ for (int i = 1; i < n; i++) {
+ differenceArray[i] = inputArray[i] - inputArray[i - 1];
+ }
+ }
+
+ /**
+ * Adds a value to all elements in the range [l, r].
+ *
+ *
+ * This method uses a branchless approach by allocating an extra element at the end
+ * of the array, avoiding the conditional check for the right boundary.
+ *
+ *
+ * @param l The starting index (inclusive).
+ * @param r The ending index (inclusive).
+ * @param val The value to add.
+ * @throws IllegalArgumentException if the range is invalid.
+ */
+ public void update(int l, int r, int val) {
+ if (l < 0 || r >= n || l > r) {
+ throw new IllegalArgumentException(String.format("Invalid range: [%d, %d] for array of size %d", l, r, n));
+ }
+
+ differenceArray[l] += val;
+ differenceArray[r + 1] -= val;
+ }
+
+ /**
+ * Reconstructs the final array using prefix sums.
+ *
+ * @return The resulting array after all updates. Returns long[] to handle potential overflows.
+ */
+ public long[] getResultArray() {
+ long[] result = new long[n];
+ result[0] = differenceArray[0];
+
+ for (int i = 1; i < n; i++) {
+ result[i] = differenceArray[i] + result[i - 1];
+ }
+ return result;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/prefixsum/DifferenceArrayTest.java b/src/test/java/com/thealgorithms/prefixsum/DifferenceArrayTest.java
new file mode 100644
index 000000000000..88a480f25f1a
--- /dev/null
+++ b/src/test/java/com/thealgorithms/prefixsum/DifferenceArrayTest.java
@@ -0,0 +1,110 @@
+package com.thealgorithms.prefixsum;
+
+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.Test;
+
+class DifferenceArrayTest {
+
+ @Test
+ void testStandardRangeUpdate() {
+ int[] input = {10, 20, 30, 40, 50};
+ DifferenceArray da = new DifferenceArray(input);
+
+ da.update(1, 3, 5);
+
+ long[] expected = {10, 25, 35, 45, 50};
+ assertArrayEquals(expected, da.getResultArray());
+ }
+
+ @Test
+ void testMultipleOverlappingUpdates() {
+ int[] input = {10, 10, 10, 10, 10};
+ DifferenceArray da = new DifferenceArray(input);
+
+ da.update(0, 2, 10);
+ da.update(2, 4, 20);
+
+ long[] expected = {20, 20, 40, 30, 30};
+ assertArrayEquals(expected, da.getResultArray());
+ }
+
+ @Test
+ void testIntegerOverflowSafety() {
+ int[] input = {Integer.MAX_VALUE, 100};
+ DifferenceArray da = new DifferenceArray(input);
+
+ da.update(0, 0, 100);
+
+ long[] result = da.getResultArray();
+ long expectedVal = (long) Integer.MAX_VALUE + 100;
+
+ assertEquals(expectedVal, result[0]);
+ }
+
+ @Test
+ void testFullRangeUpdate() {
+ int[] input = {1, 2, 3};
+ DifferenceArray da = new DifferenceArray(input);
+
+ da.update(0, 2, 100);
+
+ long[] expected = {101, 102, 103};
+ assertArrayEquals(expected, da.getResultArray());
+ }
+
+ @Test
+ void testBoundaryWriteOptimization() {
+ int[] input = {5, 5};
+ DifferenceArray da = new DifferenceArray(input);
+
+ da.update(1, 1, 5);
+
+ long[] expected = {5, 10};
+
+ assertArrayEquals(expected, da.getResultArray());
+ }
+
+ @Test
+ void testLargeMassiveUpdate() {
+ int[] input = {0};
+ DifferenceArray da = new DifferenceArray(input);
+
+ int iterations = 100000;
+ for (int i = 0; i < iterations; i++) {
+ da.update(0, 0, 1);
+ }
+
+ assertEquals(100000L, da.getResultArray()[0]);
+ }
+
+ @Test
+ void testNullInputThrowsException() {
+ assertThrows(IllegalArgumentException.class, () -> new DifferenceArray(null));
+ }
+
+ @Test
+ void testEmptyInputThrowsException() {
+ assertThrows(IllegalArgumentException.class, () -> new DifferenceArray(new int[] {}));
+ }
+
+ @Test
+ void testInvalidRangeNegativeIndex() {
+ DifferenceArray da = new DifferenceArray(new int[] {1, 2, 3});
+ assertThrows(IllegalArgumentException.class, () -> da.update(-1, 1, 5));
+ }
+
+ @Test
+ void testInvalidRangeOutOfBounds() {
+ DifferenceArray da = new DifferenceArray(new int[] {1, 2, 3});
+ assertThrows(IllegalArgumentException.class, () -> da.update(0, 3, 5));
+ }
+
+ @Test
+ void testInvalidRangeStartGreaterThanEnd() {
+ DifferenceArray da = new DifferenceArray(new int[] {1, 2, 3});
+ assertThrows(IllegalArgumentException.class, () -> da.update(2, 1, 5));
+ }
+}
From 11eec787702199795249905d6f624b757f37cc07 Mon Sep 17 00:00:00 2001
From: Pranav Ghorpade <153404855+ghorpadeire@users.noreply.github.com>
Date: Fri, 30 Jan 2026 19:01:10 +0000
Subject: [PATCH 19/58] docs: Add comprehensive documentation to BinarySearch
algorithm (#7245)
* docs: Add comprehensive documentation to BinarySearch algorithm
- Added detailed JavaDoc with @param, @return, @throws tags
- Included step-by-step algorithm walkthrough example
- Added inline comments explaining each code section
- Documented time and space complexity analysis
- Provided concrete usage examples with expected outputs
- Explained edge cases and overflow prevention technique
* style: Apply proper Java formatting to BinarySearch
- Fixed line length to meet style guidelines
- Applied proper JavaDoc formatting
- Corrected indentation and spacing
- Ensured compliance with project formatting standards
* fix: correct Javadoc formatting and add missing newline at EOF
- Fix Javadoc structure with proper tag ordering (description before @params)
- Remove incorrect @throws tag (method returns -1, doesn't throw)
- Format algorithm steps as proper HTML ordered list
- Move complexity analysis before @param tags
- Add missing newline at end of file
- Fix example code to use instance method call
---
.../thealgorithms/searches/BinarySearch.java | 114 ++++++++++++++----
1 file changed, 90 insertions(+), 24 deletions(-)
diff --git a/src/main/java/com/thealgorithms/searches/BinarySearch.java b/src/main/java/com/thealgorithms/searches/BinarySearch.java
index 0cac484d56b4..7a5361b280ea 100644
--- a/src/main/java/com/thealgorithms/searches/BinarySearch.java
+++ b/src/main/java/com/thealgorithms/searches/BinarySearch.java
@@ -3,14 +3,32 @@
import com.thealgorithms.devutils.searches.SearchAlgorithm;
/**
- * Binary search is one of the most popular algorithms The algorithm finds the
- * position of a target value within a sorted array
- * IMPORTANT
- * This algorithm works correctly only if the input array is sorted
- * in ascending order.
- *
- * Worst-case performance O(log n) Best-case performance O(1) Average
- * performance O(log n) Worst-case space complexity O(1)
+ * Binary Search Algorithm Implementation
+ *
+ *
Binary search is one of the most efficient searching algorithms for finding a target element
+ * in a SORTED array. It works by repeatedly dividing the search space in half, eliminating half of
+ * the remaining elements in each step.
+ *
+ *
IMPORTANT: This algorithm ONLY works correctly if the input array is sorted in ascending
+ * order.
+ *
+ *
Algorithm Overview: 1. Start with the entire array (left = 0, right = array.length - 1) 2.
+ * Calculate the middle index 3. Compare the middle element with the target: - If middle element
+ * equals target: Found! Return the index - If middle element is less than target: Search the right
+ * half - If middle element is greater than target: Search the left half 4. Repeat until element is
+ * found or search space is exhausted
+ *
+ *
Performance Analysis: - Best-case time complexity: O(1) - Element found at middle on first
+ * try - Average-case time complexity: O(log n) - Most common scenario - Worst-case time
+ * complexity: O(log n) - Element not found or at extreme end - Space complexity: O(1) - Only uses
+ * a constant amount of extra space
+ *
+ *
Example Walkthrough: Array: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] Target: 7
+ *
+ *
Step 1: left=0, right=9, mid=4, array[4]=9 (9 > 7, search left half) Step 2: left=0,
+ * right=3, mid=1, array[1]=3 (3 < 7, search right half) Step 3: left=2, right=3, mid=2,
+ * array[2]=5 (5 < 7, search right half) Step 4: left=3, right=3, mid=3, array[3]=7 (Found!
+ * Return index 3)
*
* @author Varun Upadhyay (https://github.com/varunu28)
* @author Podshivalov Nikita (https://github.com/nikitap492)
@@ -20,41 +38,89 @@
class BinarySearch implements SearchAlgorithm {
/**
- * @param array is an array where the element should be found
- * @param key is an element which should be found
- * @param is any comparable type
- * @return index of the element
+ * Generic method to perform binary search on any comparable type. This is the main entry point
+ * for binary search operations.
+ *
+ * Example Usage:
+ *
+ * Integer[] numbers = {1, 3, 5, 7, 9, 11};
+ * int result = new BinarySearch().find(numbers, 7);
+ * // result will be 3 (index of element 7)
+ *
+ * int notFound = new BinarySearch().find(numbers, 4);
+ * // notFound will be -1 (element 4 does not exist)
+ *
+ *
+ * @param The type of elements in the array (must be Comparable)
+ * @param array The sorted array to search in (MUST be sorted in ascending order)
+ * @param key The element to search for
+ * @return The index of the key if found, -1 if not found or if array is null/empty
*/
@Override
public > int find(T[] array, T key) {
+ // Handle edge case: empty array
if (array == null || array.length == 0) {
return -1;
}
+
+ // Delegate to the core search implementation
return search(array, key, 0, array.length - 1);
}
/**
- * This method implements the Generic Binary Search
+ * Core recursive implementation of binary search algorithm. This method divides the problem
+ * into smaller subproblems recursively.
+ *
+ * How it works:
+ *
+ * - Calculate the middle index to avoid integer overflow
+ * - Check if middle element matches the target
+ * - If not, recursively search either left or right half
+ * - Base case: left > right means element not found
+ *
+ *
+ * Time Complexity: O(log n) because we halve the search space each time.
+ * Space Complexity: O(log n) due to recursive call stack.
*
- * @param array The array to make the binary search
- * @param key The number you are looking for
- * @param left The lower bound
- * @param right The upper bound
- * @return the location of the key
+ * @param The type of elements (must be Comparable)
+ * @param array The sorted array to search in
+ * @param key The element we're looking for
+ * @param left The leftmost index of current search range (inclusive)
+ * @param right The rightmost index of current search range (inclusive)
+ * @return The index where key is located, or -1 if not found
*/
private > int search(T[] array, T key, int left, int right) {
+ // Base case: Search space is exhausted
+ // This happens when left pointer crosses right pointer
if (right < left) {
- return -1; // this means that the key not found
+ return -1; // Key not found in the array
}
- // find median
- int median = (left + right) >>> 1;
+
+ // Calculate middle index
+ // Using (left + right) / 2 could cause integer overflow for large arrays
+ // So we use: left + (right - left) / 2 which is mathematically equivalent
+ // but prevents overflow
+ int median = (left + right) >>> 1; // Unsigned right shift is faster division by 2
+
+ // Get the value at middle position for comparison
int comp = key.compareTo(array[median]);
+ // Case 1: Found the target element at middle position
if (comp == 0) {
- return median;
- } else if (comp < 0) {
+ return median; // Return the index where element was found
+ }
+ // Case 2: Target is smaller than middle element
+ // This means if target exists, it must be in the LEFT half
+ else if (comp < 0) {
+ // Recursively search the left half
+ // New search range: [left, median - 1]
return search(array, key, left, median - 1);
- } else {
+ }
+ // Case 3: Target is greater than middle element
+ // This means if target exists, it must be in the RIGHT half
+ else {
+ // Recursively search the right half
+ // New search range: [median + 1, right]
return search(array, key, median + 1, right);
}
}
From f3fd9ca3851c974afb7bfafc197a45d7e3678594 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 31 Jan 2026 19:32:08 +0100
Subject: [PATCH 20/58] chore(deps): bump com.puppycrawl.tools:checkstyle from
13.0.0 to 13.1.0 (#7251)
Bumps [com.puppycrawl.tools:checkstyle](https://github.com/checkstyle/checkstyle) from 13.0.0 to 13.1.0.
- [Release notes](https://github.com/checkstyle/checkstyle/releases)
- [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-13.0.0...checkstyle-13.1.0)
---
updated-dependencies:
- dependency-name: com.puppycrawl.tools:checkstyle
dependency-version: 13.1.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 170e3900b77f..65a8fc229647 100644
--- a/pom.xml
+++ b/pom.xml
@@ -112,7 +112,7 @@
com.puppycrawl.tools
checkstyle
- 13.0.0
+ 13.1.0
From dfaa4956392b06bb2e55578e883213a9ea946b8f Mon Sep 17 00:00:00 2001
From: Divyansh Saxena <119129875+divyanshsaxena002@users.noreply.github.com>
Date: Sun, 1 Feb 2026 20:21:13 +0530
Subject: [PATCH 21/58] Refactor KMP and RabinKarp: Improve Reusability and
Test Coverage (#7250)
* first commit
* Running KMPTest and RabinKarpTest with fixed formatting
* now build failed error resolved
* now build failed error resolved 2
---------
Co-authored-by: Divyansh Saxena
Co-authored-by: Deniz Altunkapan
---
.../java/com/thealgorithms/strings/KMP.java | 27 +++++---
.../com/thealgorithms/strings/RabinKarp.java | 62 ++++++++-----------
.../com/thealgorithms/strings/KMPTest.java | 29 +++++++++
.../thealgorithms/strings/RabinKarpTest.java | 46 ++++++++++++++
4 files changed, 119 insertions(+), 45 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/strings/KMPTest.java
create mode 100644 src/test/java/com/thealgorithms/strings/RabinKarpTest.java
diff --git a/src/main/java/com/thealgorithms/strings/KMP.java b/src/main/java/com/thealgorithms/strings/KMP.java
index 07d3b0415006..0317abe6f39a 100644
--- a/src/main/java/com/thealgorithms/strings/KMP.java
+++ b/src/main/java/com/thealgorithms/strings/KMP.java
@@ -1,5 +1,8 @@
package com.thealgorithms.strings;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Implementation of Knuth–Morris–Pratt algorithm Usage: see the main function
* for an example
@@ -8,16 +11,19 @@ public final class KMP {
private KMP() {
}
- // a working example
-
- public static void main(String[] args) {
- final String haystack = "AAAAABAAABA"; // This is the full string
- final String needle = "AAAA"; // This is the substring that we want to find
- kmpMatcher(haystack, needle);
- }
+ /**
+ * find the starting index in string haystack[] that matches the search word P[]
+ *
+ * @param haystack The text to be searched
+ * @param needle The pattern to be searched for
+ * @return A list of starting indices where the pattern is found
+ */
+ public static List kmpMatcher(final String haystack, final String needle) {
+ List occurrences = new ArrayList<>();
+ if (haystack == null || needle == null || needle.isEmpty()) {
+ return occurrences;
+ }
- // find the starting index in string haystack[] that matches the search word P[]
- public static void kmpMatcher(final String haystack, final String needle) {
final int m = haystack.length();
final int n = needle.length();
final int[] pi = computePrefixFunction(needle);
@@ -32,10 +38,11 @@ public static void kmpMatcher(final String haystack, final String needle) {
}
if (q == n) {
- System.out.println("Pattern starts: " + (i + 1 - n));
+ occurrences.add(i + 1 - n);
q = pi[q - 1];
}
}
+ return occurrences;
}
// return the prefix function
diff --git a/src/main/java/com/thealgorithms/strings/RabinKarp.java b/src/main/java/com/thealgorithms/strings/RabinKarp.java
index bb8df3358453..be17f87c3656 100644
--- a/src/main/java/com/thealgorithms/strings/RabinKarp.java
+++ b/src/main/java/com/thealgorithms/strings/RabinKarp.java
@@ -1,32 +1,30 @@
package com.thealgorithms.strings;
-import java.util.Scanner;
+import java.util.ArrayList;
+import java.util.List;
/**
* @author Prateek Kumar Oraon (https://github.com/prateekKrOraon)
*
- An implementation of Rabin-Karp string matching algorithm
- Program will simply end if there is no match
+ * An implementation of Rabin-Karp string matching algorithm
+ * Program will simply end if there is no match
*/
public final class RabinKarp {
private RabinKarp() {
}
- public static Scanner scanner = null;
- public static final int ALPHABET_SIZE = 256;
+ private static final int ALPHABET_SIZE = 256;
- public static void main(String[] args) {
- scanner = new Scanner(System.in);
- System.out.println("Enter String");
- String text = scanner.nextLine();
- System.out.println("Enter pattern");
- String pattern = scanner.nextLine();
-
- int q = 101;
- searchPat(text, pattern, q);
+ public static List search(String text, String pattern) {
+ return search(text, pattern, 101);
}
- private static void searchPat(String text, String pattern, int q) {
+ public static List search(String text, String pattern, int q) {
+ List occurrences = new ArrayList<>();
+ if (text == null || pattern == null || pattern.isEmpty()) {
+ return occurrences;
+ }
+
int m = pattern.length();
int n = text.length();
int t = 0;
@@ -35,48 +33,42 @@ private static void searchPat(String text, String pattern, int q) {
int j = 0;
int i = 0;
- h = (int) Math.pow(ALPHABET_SIZE, m - 1) % q;
+ if (m > n) {
+ return new ArrayList<>();
+ }
+
+ // h = pow(ALPHABET_SIZE, m-1) % q
+ for (i = 0; i < m - 1; i++) {
+ h = h * ALPHABET_SIZE % q;
+ }
for (i = 0; i < m; i++) {
- // hash value is calculated for each character and then added with the hash value of the
- // next character for pattern as well as the text for length equal to the length of
- // pattern
p = (ALPHABET_SIZE * p + pattern.charAt(i)) % q;
t = (ALPHABET_SIZE * t + text.charAt(i)) % q;
}
for (i = 0; i <= n - m; i++) {
- // if the calculated hash value of the pattern and text matches then
- // all the characters of the pattern is matched with the text of length equal to length
- // of the pattern if all matches then pattern exist in string if not then the hash value
- // of the first character of the text is subtracted and hash value of the next character
- // after the end of the evaluated characters is added
if (p == t) {
- // if hash value matches then the individual characters are matched
for (j = 0; j < m; j++) {
- // if not matched then break out of the loop
if (text.charAt(i + j) != pattern.charAt(j)) {
break;
}
}
- // if all characters are matched then pattern exist in the string
if (j == m) {
- System.out.println("Pattern found at index " + i);
+ occurrences.add(i);
}
}
- // if i
Date: Sun, 1 Feb 2026 20:56:57 +0530
Subject: [PATCH 22/58] add Subarray Sum Equals K using prefix sum (#7252)
Co-authored-by: Deniz Altunkapan
---
.../prefixsum/SubarraySumEqualsK.java | 72 +++++++++++++++++++
.../prefixsum/SubarraySumEqualskTest.java | 59 +++++++++++++++
2 files changed, 131 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/prefixsum/SubarraySumEqualsK.java
create mode 100644 src/test/java/com/thealgorithms/prefixsum/SubarraySumEqualskTest.java
diff --git a/src/main/java/com/thealgorithms/prefixsum/SubarraySumEqualsK.java b/src/main/java/com/thealgorithms/prefixsum/SubarraySumEqualsK.java
new file mode 100644
index 000000000000..d6a6bbc01663
--- /dev/null
+++ b/src/main/java/com/thealgorithms/prefixsum/SubarraySumEqualsK.java
@@ -0,0 +1,72 @@
+package com.thealgorithms.prefixsum;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Implements an algorithm to count the number of continuous subarrays
+ * whose sum equals a given value k.
+ *
+ *
+ * This algorithm uses the Prefix Sum technique combined with a HashMap
+ * to achieve O(N) time complexity.
+ *
+ *
+ *
+ * Let prefixSum[i] be the sum of elements from index 0 to i.
+ * A subarray (j + 1) to i has sum k if:
+ *
+ *
+ * prefixSum[i] - prefixSum[j] = k
+ *
+ *
+ *
+ *
+ * The HashMap stores the frequency of each prefix sum encountered so far.
+ *
+ *
+ *
+ * Time Complexity: O(N)
+ * Space Complexity: O(N)
+ *
+ *
+ * @see Prefix Sum (Wikipedia)
+ * @author Ruturaj Jadhav, ruturajjadhav07
+ */
+public final class SubarraySumEqualsK {
+
+ private SubarraySumEqualsK() {
+ // Utility class; prevent instantiation
+ }
+
+ /**
+ * Counts the number of subarrays whose sum equals k.
+ *
+ * @param nums The input integer array.
+ * @param k The target sum.
+ * @return The number of continuous subarrays summing to k.
+ * @throws IllegalArgumentException if nums is null.
+ */
+ public static int countSubarrays(int[] nums, int k) {
+ if (nums == null) {
+ throw new IllegalArgumentException("Input array cannot be null");
+ }
+
+ Map prefixSumFrequency = new HashMap<>();
+ prefixSumFrequency.put(0L, 1);
+
+ long prefixSum = 0;
+ int count = 0;
+
+ for (int num : nums) {
+ prefixSum += num;
+
+ long requiredSum = prefixSum - k;
+ count += prefixSumFrequency.getOrDefault(requiredSum, 0);
+
+ prefixSumFrequency.put(prefixSum, prefixSumFrequency.getOrDefault(prefixSum, 0) + 1);
+ }
+
+ return count;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/prefixsum/SubarraySumEqualskTest.java b/src/test/java/com/thealgorithms/prefixsum/SubarraySumEqualskTest.java
new file mode 100644
index 000000000000..68f85b713046
--- /dev/null
+++ b/src/test/java/com/thealgorithms/prefixsum/SubarraySumEqualskTest.java
@@ -0,0 +1,59 @@
+package com.thealgorithms.prefixsum;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for {@link SubarraySumEqualsK}.
+ */
+class SubarraySumEqualsKTest {
+
+ @Test
+ void testBasicExample() {
+ int[] nums = {1, 1, 1};
+ int k = 2;
+ assertEquals(2, SubarraySumEqualsK.countSubarrays(nums, k));
+ }
+
+ @Test
+ void testWithNegativeNumbers() {
+ int[] nums = {1, -1, 0};
+ int k = 0;
+ assertEquals(3, SubarraySumEqualsK.countSubarrays(nums, k));
+ }
+
+ @Test
+ void testSingleElementEqualToK() {
+ int[] nums = {5};
+ int k = 5;
+ assertEquals(1, SubarraySumEqualsK.countSubarrays(nums, k));
+ }
+
+ @Test
+ void testSingleElementNotEqualToK() {
+ int[] nums = {5};
+ int k = 3;
+ assertEquals(0, SubarraySumEqualsK.countSubarrays(nums, k));
+ }
+
+ @Test
+ void testAllZeros() {
+ int[] nums = {0, 0, 0};
+ int k = 0;
+ assertEquals(6, SubarraySumEqualsK.countSubarrays(nums, k));
+ }
+
+ @Test
+ void testEmptyArray() {
+ int[] nums = {};
+ int k = 0;
+ assertEquals(0, SubarraySumEqualsK.countSubarrays(nums, k));
+ }
+
+ @Test
+ void testNullArrayThrowsException() {
+ assertThrows(IllegalArgumentException.class, () -> SubarraySumEqualsK.countSubarrays(null, 0));
+ }
+}
From c6703d337edb74783406d5cafa4a363a2415d8eb Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 3 Feb 2026 10:55:55 +0100
Subject: [PATCH 23/58] chore(deps-dev): bump
org.apache.maven.plugins:maven-compiler-plugin from 3.14.1 to 3.15.0 (#7254)
chore(deps-dev): bump org.apache.maven.plugins:maven-compiler-plugin
Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.14.1 to 3.15.0.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.14.1...maven-compiler-plugin-3.15.0)
---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-compiler-plugin
dependency-version: 3.15.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>
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 65a8fc229647..f13169cece97 100644
--- a/pom.xml
+++ b/pom.xml
@@ -69,7 +69,7 @@
org.apache.maven.plugins
maven-compiler-plugin
- 3.14.1
+ 3.15.0
21
From 8e30bcbb02f14f118cc63f24b3c44b7ff7f66ba8 Mon Sep 17 00:00:00 2001
From: Ahmed Allam <60698204+GziXnine@users.noreply.github.com>
Date: Tue, 3 Feb 2026 22:32:37 +0200
Subject: [PATCH 24/58] refactor: clean up duplicate algorithm implementations
to reduce maintenance overhead (#7256)
refactor: remove duplicate algorithm implementations
Removed the following duplicate implementations:
- searches/PerfectBinarySearch.java (duplicate of IterativeBinarySearch)
- searches/SortOrderAgnosticBinarySearch.java (duplicate of OrderAgnosticBinarySearch)
- strings/LongestPalindromicSubstring.java (duplicate of dynamicprogramming version)
- strings/ValidParentheses.java (duplicate of stacks version)
- others/cn/HammingDistance.java (duplicate - strings version handles text)
- others/NewManShanksPrimeTest.java (orphan test in wrong package)
Updated DIRECTORY.md to reflect the changes.
Fixes #7253
Co-authored-by: Ahmed Allam <60698204+AllamF5J@users.noreply.github.com>
---
DIRECTORY.md | 13 ---
.../others/cn/HammingDistance.java | 32 --------
.../searches/PerfectBinarySearch.java | 54 ------------
.../SortOrderAgnosticBinarySearch.java | 30 -------
.../strings/LongestPalindromicSubstring.java | 37 ---------
.../strings/ValidParentheses.java | 53 ------------
.../others/NewManShanksPrimeTest.java | 49 -----------
.../others/cn/HammingDistanceTest.java | 82 -------------------
.../searches/PerfectBinarySearchTest.java | 44 ----------
.../SortOrderAgnosticBinarySearchTest.java | 26 ------
.../LongestPalindromicSubstringTest.java | 21 -----
.../strings/ValidParenthesesTest.java | 33 --------
12 files changed, 474 deletions(-)
delete mode 100644 src/main/java/com/thealgorithms/others/cn/HammingDistance.java
delete mode 100644 src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java
delete mode 100644 src/main/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearch.java
delete mode 100644 src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java
delete mode 100644 src/main/java/com/thealgorithms/strings/ValidParentheses.java
delete mode 100644 src/test/java/com/thealgorithms/others/NewManShanksPrimeTest.java
delete mode 100644 src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java
delete mode 100644 src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java
delete mode 100644 src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java
delete mode 100644 src/test/java/com/thealgorithms/strings/LongestPalindromicSubstringTest.java
delete mode 100644 src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index deaf59636fa4..585c634c3429 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -626,8 +626,6 @@
- 📄 [SkylineProblem](src/main/java/com/thealgorithms/others/SkylineProblem.java)
- 📄 [TwoPointers](src/main/java/com/thealgorithms/others/TwoPointers.java)
- 📄 [Verhoeff](src/main/java/com/thealgorithms/others/Verhoeff.java)
- - 📁 **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)
@@ -701,7 +699,6 @@
- 📄 [LowerBound](src/main/java/com/thealgorithms/searches/LowerBound.java)
- 📄 [MonteCarloTreeSearch](src/main/java/com/thealgorithms/searches/MonteCarloTreeSearch.java)
- 📄 [OrderAgnosticBinarySearch](src/main/java/com/thealgorithms/searches/OrderAgnosticBinarySearch.java)
- - 📄 [PerfectBinarySearch](src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java)
- 📄 [QuickSelect](src/main/java/com/thealgorithms/searches/QuickSelect.java)
- 📄 [RabinKarpAlgorithm](src/main/java/com/thealgorithms/searches/RabinKarpAlgorithm.java)
- 📄 [RandomSearch](src/main/java/com/thealgorithms/searches/RandomSearch.java)
@@ -710,7 +707,6 @@
- 📄 [SaddlebackSearch](src/main/java/com/thealgorithms/searches/SaddlebackSearch.java)
- 📄 [SearchInARowAndColWiseSortedMatrix](src/main/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrix.java)
- 📄 [SentinelLinearSearch](src/main/java/com/thealgorithms/searches/SentinelLinearSearch.java)
- - 📄 [SortOrderAgnosticBinarySearch](src/main/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearch.java)
- 📄 [SquareRootBinarySearch](src/main/java/com/thealgorithms/searches/SquareRootBinarySearch.java)
- 📄 [TernarySearch](src/main/java/com/thealgorithms/searches/TernarySearch.java)
- 📄 [UnionFind](src/main/java/com/thealgorithms/searches/UnionFind.java)
@@ -817,7 +813,6 @@
- 📄 [LetterCombinationsOfPhoneNumber](src/main/java/com/thealgorithms/strings/LetterCombinationsOfPhoneNumber.java)
- 📄 [LongestCommonPrefix](src/main/java/com/thealgorithms/strings/LongestCommonPrefix.java)
- 📄 [LongestNonRepetitiveSubstring](src/main/java/com/thealgorithms/strings/LongestNonRepetitiveSubstring.java)
- - 📄 [LongestPalindromicSubstring](src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java)
- 📄 [Lower](src/main/java/com/thealgorithms/strings/Lower.java)
- 📄 [Manacher](src/main/java/com/thealgorithms/strings/Manacher.java)
- 📄 [MyAtoi](src/main/java/com/thealgorithms/strings/MyAtoi.java)
@@ -834,7 +829,6 @@
- 📄 [StringMatchFiniteAutomata](src/main/java/com/thealgorithms/strings/StringMatchFiniteAutomata.java)
- 📄 [SuffixArray](src/main/java/com/thealgorithms/strings/SuffixArray.java)
- 📄 [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**
@@ -1395,7 +1389,6 @@
- 📄 [MaximumSumOfDistinctSubarraysWithLengthKTest](src/test/java/com/thealgorithms/others/MaximumSumOfDistinctSubarraysWithLengthKTest.java)
- 📄 [MiniMaxAlgorithmTest](src/test/java/com/thealgorithms/others/MiniMaxAlgorithmTest.java)
- 📄 [MosAlgorithmTest](src/test/java/com/thealgorithms/others/MosAlgorithmTest.java)
- - 📄 [NewManShanksPrimeTest](src/test/java/com/thealgorithms/others/NewManShanksPrimeTest.java)
- 📄 [NextFitTest](src/test/java/com/thealgorithms/others/NextFitTest.java)
- 📄 [PageRankTest](src/test/java/com/thealgorithms/others/PageRankTest.java)
- 📄 [PasswordGenTest](src/test/java/com/thealgorithms/others/PasswordGenTest.java)
@@ -1404,8 +1397,6 @@
- 📄 [SkylineProblemTest](src/test/java/com/thealgorithms/others/SkylineProblemTest.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)
@@ -1479,7 +1470,6 @@
- 📄 [LowerBoundTest](src/test/java/com/thealgorithms/searches/LowerBoundTest.java)
- 📄 [MonteCarloTreeSearchTest](src/test/java/com/thealgorithms/searches/MonteCarloTreeSearchTest.java)
- 📄 [OrderAgnosticBinarySearchTest](src/test/java/com/thealgorithms/searches/OrderAgnosticBinarySearchTest.java)
- - 📄 [PerfectBinarySearchTest](src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java)
- 📄 [QuickSelectTest](src/test/java/com/thealgorithms/searches/QuickSelectTest.java)
- 📄 [RabinKarpAlgorithmTest](src/test/java/com/thealgorithms/searches/RabinKarpAlgorithmTest.java)
- 📄 [RandomSearchTest](src/test/java/com/thealgorithms/searches/RandomSearchTest.java)
@@ -1488,7 +1478,6 @@
- 📄 [SaddlebackSearchTest](src/test/java/com/thealgorithms/searches/SaddlebackSearchTest.java)
- 📄 [SearchInARowAndColWiseSortedMatrixTest](src/test/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrixTest.java)
- 📄 [SentinelLinearSearchTest](src/test/java/com/thealgorithms/searches/SentinelLinearSearchTest.java)
- - 📄 [SortOrderAgnosticBinarySearchTest](src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java)
- 📄 [SquareRootBinarySearchTest](src/test/java/com/thealgorithms/searches/SquareRootBinarySearchTest.java)
- 📄 [TernarySearchTest](src/test/java/com/thealgorithms/searches/TernarySearchTest.java)
- 📄 [TestSearchInARowAndColWiseSortedMatrix](src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java)
@@ -1593,7 +1582,6 @@
- 📄 [LetterCombinationsOfPhoneNumberTest](src/test/java/com/thealgorithms/strings/LetterCombinationsOfPhoneNumberTest.java)
- 📄 [LongestCommonPrefixTest](src/test/java/com/thealgorithms/strings/LongestCommonPrefixTest.java)
- 📄 [LongestNonRepetitiveSubstringTest](src/test/java/com/thealgorithms/strings/LongestNonRepetitiveSubstringTest.java)
- - 📄 [LongestPalindromicSubstringTest](src/test/java/com/thealgorithms/strings/LongestPalindromicSubstringTest.java)
- 📄 [LowerTest](src/test/java/com/thealgorithms/strings/LowerTest.java)
- 📄 [ManacherTest](src/test/java/com/thealgorithms/strings/ManacherTest.java)
- 📄 [MyAtoiTest](src/test/java/com/thealgorithms/strings/MyAtoiTest.java)
@@ -1609,7 +1597,6 @@
- 📄 [StringMatchFiniteAutomataTest](src/test/java/com/thealgorithms/strings/StringMatchFiniteAutomataTest.java)
- 📄 [SuffixArrayTest](src/test/java/com/thealgorithms/strings/SuffixArrayTest.java)
- 📄 [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**
diff --git a/src/main/java/com/thealgorithms/others/cn/HammingDistance.java b/src/main/java/com/thealgorithms/others/cn/HammingDistance.java
deleted file mode 100644
index c8239d53d606..000000000000
--- a/src/main/java/com/thealgorithms/others/cn/HammingDistance.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.thealgorithms.others.cn;
-
-public final class HammingDistance {
- private HammingDistance() {
- }
-
- private static void checkChar(char inChar) {
- if (inChar != '0' && inChar != '1') {
- throw new IllegalArgumentException("Input must be a binary string.");
- }
- }
-
- public static int compute(char charA, char charB) {
- checkChar(charA);
- checkChar(charB);
- return charA == charB ? 0 : 1;
- }
-
- public static int compute(String bitsStrA, String bitsStrB) {
- if (bitsStrA.length() != bitsStrB.length()) {
- throw new IllegalArgumentException("Input strings must have the same length.");
- }
-
- int totalErrorBitCount = 0;
-
- for (int i = 0; i < bitsStrA.length(); i++) {
- totalErrorBitCount += compute(bitsStrA.charAt(i), bitsStrB.charAt(i));
- }
-
- return totalErrorBitCount;
- }
-}
diff --git a/src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java b/src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java
deleted file mode 100644
index 495e2e41bc5b..000000000000
--- a/src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.thealgorithms.searches;
-
-import com.thealgorithms.devutils.searches.SearchAlgorithm;
-
-/**
- * Binary search is one of the most popular algorithms The algorithm finds the
- * position of a target value within a sorted array
- *
- *
- * Worst-case performance O(log n) Best-case performance O(1) Average
- * performance O(log n) Worst-case space complexity O(1)
- *
- * @author D Sunil (https://github.com/sunilnitdgp)
- * @see SearchAlgorithm
- */
-
-public class PerfectBinarySearch implements SearchAlgorithm {
-
- /**
- * @param array is an array where the element should be found
- * @param key is an element which should be found
- * @param is any comparable type
- * @return index of the element
- */
- @Override
- public > int find(T[] array, T key) {
- return search(array, key, 0, array.length - 1);
- }
-
- /**
- * This method implements the Generic Binary Search iteratively.
- *
- * @param array The array to make the binary search
- * @param key The number you are looking for
- * @return the location of the key, or -1 if not found
- */
- private static > int search(T[] array, T key, int left, int right) {
- while (left <= right) {
- int median = (left + right) >>> 1;
- int comp = key.compareTo(array[median]);
-
- if (comp == 0) {
- return median; // Key found
- }
-
- if (comp < 0) {
- right = median - 1; // Adjust the right bound
- } else {
- left = median + 1; // Adjust the left bound
- }
- }
- return -1; // Key not found
- }
-}
diff --git a/src/main/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearch.java b/src/main/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearch.java
deleted file mode 100644
index 6a2a46c2821f..000000000000
--- a/src/main/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearch.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.thealgorithms.searches;
-public final class SortOrderAgnosticBinarySearch {
- private SortOrderAgnosticBinarySearch() {
- }
- public static int find(int[] arr, int key) {
- int start = 0;
- int end = arr.length - 1;
- boolean arrDescending = arr[start] > arr[end]; // checking for Array is in ascending order or descending order.
- while (start <= end) {
- int mid = end - start / 2;
- if (arr[mid] == key) {
- return mid;
- }
- if (arrDescending) { // boolean is true then our array is in descending order
- if (key < arr[mid]) {
- start = mid + 1;
- } else {
- end = mid - 1;
- }
- } else { // otherwise our array is in ascending order
- if (key > arr[mid]) {
- start = mid + 1;
- } else {
- end = mid - 1;
- }
- }
- }
- return -1;
- }
-}
diff --git a/src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java b/src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java
deleted file mode 100644
index ca500357ba77..000000000000
--- a/src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.thealgorithms.strings;
-
-final class LongestPalindromicSubstring {
- private LongestPalindromicSubstring() {
- }
-
- /**
- * Finds the longest palindromic substring in the given string.
- *
- * @param s the input string
- * @return the longest palindromic substring
- */
- public static String longestPalindrome(String s) {
- if (s == null || s.isEmpty()) {
- return "";
- }
- String maxStr = "";
- for (int i = 0; i < s.length(); ++i) {
- for (int j = i; j < s.length(); ++j) {
- if (isValid(s, i, j) && (j - i + 1 > maxStr.length())) {
- maxStr = s.substring(i, j + 1);
- }
- }
- }
- return maxStr;
- }
-
- private static boolean isValid(String s, int lo, int hi) {
- int n = hi - lo + 1;
- for (int i = 0; i < n / 2; ++i) {
- if (s.charAt(lo + i) != s.charAt(hi - i)) {
- return false;
- }
- }
- return true;
- }
-}
diff --git a/src/main/java/com/thealgorithms/strings/ValidParentheses.java b/src/main/java/com/thealgorithms/strings/ValidParentheses.java
deleted file mode 100644
index 25a72f379dec..000000000000
--- a/src/main/java/com/thealgorithms/strings/ValidParentheses.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.thealgorithms.strings;
-
-import java.util.ArrayDeque;
-import java.util.Deque;
-import java.util.Map;
-
-/**
- * Validates if a given string has valid matching parentheses.
- *
- * A string is considered valid if:
- *
- * - Open brackets are closed by the same type of brackets.
- * - Brackets are closed in the correct order.
- * - Every closing bracket has a corresponding open bracket of the same type.
- *
- *
- * Allowed characters: '(', ')', '{', '}', '[', ']'
- */
-public final class ValidParentheses {
- private ValidParentheses() {
- }
-
- private static final Map BRACKET_PAIRS = Map.of(')', '(', '}', '{', ']', '[');
-
- /**
- * Checks if the input string has valid parentheses.
- *
- * @param s the string containing only bracket characters
- * @return true if valid, false otherwise
- * @throws IllegalArgumentException if the string contains invalid characters or is null
- */
- public static boolean isValid(String s) {
- if (s == null) {
- throw new IllegalArgumentException("Input string cannot be null");
- }
-
- Deque stack = new ArrayDeque<>();
-
- for (char c : s.toCharArray()) {
- if (BRACKET_PAIRS.containsValue(c)) {
- stack.push(c); // opening bracket
- } else if (BRACKET_PAIRS.containsKey(c)) {
- if (stack.isEmpty() || stack.pop() != BRACKET_PAIRS.get(c)) {
- return false;
- }
- } else {
- throw new IllegalArgumentException("Unexpected character: " + c);
- }
- }
-
- return stack.isEmpty();
- }
-}
diff --git a/src/test/java/com/thealgorithms/others/NewManShanksPrimeTest.java b/src/test/java/com/thealgorithms/others/NewManShanksPrimeTest.java
deleted file mode 100644
index 3b657e441b1c..000000000000
--- a/src/test/java/com/thealgorithms/others/NewManShanksPrimeTest.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.thealgorithms.others;
-
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import com.thealgorithms.dynamicprogramming.NewManShanksPrime;
-import org.junit.jupiter.api.Test;
-
-public class NewManShanksPrimeTest {
-
- @Test
- void testOne() {
- assertTrue(NewManShanksPrime.nthManShanksPrime(1, 1));
- }
-
- @Test
- void testTwo() {
- assertTrue(NewManShanksPrime.nthManShanksPrime(2, 3));
- }
-
- @Test
- void testThree() {
- assertTrue(NewManShanksPrime.nthManShanksPrime(3, 7));
- }
-
- @Test
- void testFour() {
- assertTrue(NewManShanksPrime.nthManShanksPrime(4, 17));
- }
-
- @Test
- void testFive() {
- assertTrue(NewManShanksPrime.nthManShanksPrime(5, 41));
- }
-
- @Test
- void testSix() {
- assertTrue(NewManShanksPrime.nthManShanksPrime(6, 99));
- }
-
- @Test
- void testSeven() {
- assertTrue(NewManShanksPrime.nthManShanksPrime(7, 239));
- }
-
- @Test
- void testEight() {
- assertTrue(NewManShanksPrime.nthManShanksPrime(8, 577));
- }
-}
diff --git a/src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java b/src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java
deleted file mode 100644
index 669f928cd247..000000000000
--- a/src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.thealgorithms.others.cn;
-
-import org.assertj.core.api.Assertions;
-import org.junit.jupiter.api.Test;
-
-public class HammingDistanceTest {
- @Test
- public void checkForDifferentBits() {
- int answer = HammingDistance.compute("000", "011");
- Assertions.assertThat(answer).isEqualTo(2);
- }
-
- /*
-
- 1 0 1 0 1
- 1 1 1 1 0
- ----------
- 0 1 0 1 1
-
-
- */
- @Test
- public void checkForDifferentBitsLength() {
- int answer = HammingDistance.compute("10101", "11110");
- Assertions.assertThat(answer).isEqualTo(3);
- }
-
- @Test
- public void checkForSameBits() {
- String someBits = "111";
- int answer = HammingDistance.compute(someBits, someBits);
- Assertions.assertThat(answer).isEqualTo(0);
- }
-
- @Test
- public void checkForLongDataBits() {
- int answer = HammingDistance.compute("10010101101010000100110100", "00110100001011001100110101");
- Assertions.assertThat(answer).isEqualTo(7);
- }
-
- @Test
- public void mismatchDataBits() {
- Exception ex = org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, () -> { HammingDistance.compute("100010", "00011"); });
-
- Assertions.assertThat(ex.getMessage()).contains("must have the same length");
- }
-
- @Test
- public void mismatchDataBits2() {
- Exception ex = org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, () -> { HammingDistance.compute("1", "11"); });
-
- Assertions.assertThat(ex.getMessage()).contains("must have the same length");
- }
-
- @Test
- public void checkForLongDataBitsSame() {
- String someBits = "10010101101010000100110100";
- int answer = HammingDistance.compute(someBits, someBits);
- Assertions.assertThat(answer).isEqualTo(0);
- }
-
- @Test
- public void checkForEmptyInput() {
- String someBits = "";
- int answer = HammingDistance.compute(someBits, someBits);
- Assertions.assertThat(answer).isEqualTo(0);
- }
-
- @Test
- public void checkForInputOfLength1() {
- String someBits = "0";
- int answer = HammingDistance.compute(someBits, someBits);
- Assertions.assertThat(answer).isEqualTo(0);
- }
-
- @Test
- public void computeThrowsExceptionWhenInputsAreNotBitStrs() {
- Exception ex = org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, () -> { HammingDistance.compute("1A", "11"); });
-
- Assertions.assertThat(ex.getMessage()).contains("must be a binary string");
- }
-}
diff --git a/src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java b/src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java
deleted file mode 100644
index 6eab20f45467..000000000000
--- a/src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.thealgorithms.searches;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import org.junit.jupiter.api.Test;
-
-/**
- * @author D Sunil (https://github.com/sunilnitdgp)
- * @see PerfectBinarySearch
- */
-public class PerfectBinarySearchTest {
-
- @Test
- public void testIntegerBinarySearch() {
- Integer[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
- PerfectBinarySearch binarySearch = new PerfectBinarySearch<>();
-
- // Test cases for elements present in the array
- assertEquals(0, binarySearch.find(array, 1)); // First element
- assertEquals(4, binarySearch.find(array, 5)); // Middle element
- assertEquals(9, binarySearch.find(array, 10)); // Last element
- assertEquals(6, binarySearch.find(array, 7)); // Element in the middle
-
- // Test cases for elements not in the array
- assertEquals(-1, binarySearch.find(array, 0)); // Element before the array
- assertEquals(-1, binarySearch.find(array, 11)); // Element after the array
- assertEquals(-1, binarySearch.find(array, 100)); // Element not in the array
- }
-
- @Test
- public void testStringBinarySearch() {
- String[] array = {"apple", "banana", "cherry", "date", "fig"};
- PerfectBinarySearch binarySearch = new PerfectBinarySearch<>();
-
- // Test cases for elements not in the array
- assertEquals(-1, binarySearch.find(array, "apricot")); // Element not in the array
- assertEquals(-1, binarySearch.find(array, "bananaa")); // Element not in the array
-
- // Test cases for elements present in the array
- assertEquals(0, binarySearch.find(array, "apple")); // First element
- assertEquals(2, binarySearch.find(array, "cherry")); // Middle element
- assertEquals(4, binarySearch.find(array, "fig")); // Last element
- }
-}
diff --git a/src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java b/src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java
deleted file mode 100644
index e2917733d1d9..000000000000
--- a/src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.thealgorithms.searches;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import org.junit.jupiter.api.Test;
-
-public class SortOrderAgnosticBinarySearchTest {
-
- @Test
- public void testAscending() {
- int[] arr = {1, 2, 3, 4, 5}; // for ascending order.
- int target = 2;
- int ans = SortOrderAgnosticBinarySearch.find(arr, target);
- int excepted = 1;
- assertEquals(excepted, ans);
- }
-
- @Test
- public void testDescending() {
- int[] arr = {5, 4, 3, 2, 1}; // for descending order.
- int target = 2;
- int ans = SortOrderAgnosticBinarySearch.find(arr, target);
- int excepted = 3;
- assertEquals(excepted, ans);
- }
-}
diff --git a/src/test/java/com/thealgorithms/strings/LongestPalindromicSubstringTest.java b/src/test/java/com/thealgorithms/strings/LongestPalindromicSubstringTest.java
deleted file mode 100644
index aa13c0f4a474..000000000000
--- a/src/test/java/com/thealgorithms/strings/LongestPalindromicSubstringTest.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.thealgorithms.strings;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import java.util.stream.Stream;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
-
-class LongestPalindromicSubstringTest {
-
- @ParameterizedTest
- @MethodSource("provideTestCasesForLongestPalindrome")
- void testLongestPalindrome(String input, String expected) {
- assertEquals(expected, LongestPalindromicSubstring.longestPalindrome(input));
- }
-
- private static Stream provideTestCasesForLongestPalindrome() {
- return Stream.of(Arguments.of("babad", "bab"), Arguments.of("cbbd", "bb"), Arguments.of("a", "a"), Arguments.of("", ""), Arguments.of("abc", "a"), Arguments.of(null, ""), Arguments.of("aaaaa", "aaaaa"));
- }
-}
diff --git a/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java b/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java
deleted file mode 100644
index 411b11e743b8..000000000000
--- a/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.thealgorithms.strings;
-
-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;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.CsvSource;
-
-public class ValidParenthesesTest {
-
- @ParameterizedTest(name = "Input: \"{0}\" → Expected: {1}")
- @CsvSource({"'()', true", "'()[]{}', true", "'(]', false", "'{[]}', true", "'([{}])', true", "'([)]', false", "'', true", "'(', false", "')', false", "'{{{{}}}}', true", "'[({})]', true", "'[(])', false", "'[', false", "']', false", "'()()()()', true", "'(()', false", "'())', false",
- "'{[()()]()}', true"})
- void
- testIsValid(String input, boolean expected) {
- assertEquals(expected, ValidParentheses.isValid(input));
- }
-
- @Test
- void testNullInputThrows() {
- IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> ValidParentheses.isValid(null));
- assertEquals("Input string cannot be null", ex.getMessage());
- }
-
- @ParameterizedTest(name = "Input: \"{0}\" → throws IllegalArgumentException")
- @CsvSource({"'a'", "'()a'", "'[123]'", "'{hello}'", "'( )'", "'\t'", "'\n'", "'@#$%'"})
- void testInvalidCharactersThrow(String input) {
- IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> ValidParentheses.isValid(input));
- assertTrue(ex.getMessage().startsWith("Unexpected character"));
- }
-}
From a14b2345f0a40a043ce78ebaf1ff056bbb362891 Mon Sep 17 00:00:00 2001
From: Chahat Sandhu
Date: Wed, 4 Feb 2026 09:49:15 -0600
Subject: [PATCH 25/58] feat: add ElGamalCipher with Safe Prime generation and
stateless design (#7257)
---
.../thealgorithms/ciphers/ElGamalCipher.java | 174 ++++++++++++++++++
.../ciphers/ElGamalCipherTest.java | 145 +++++++++++++++
2 files changed, 319 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/ciphers/ElGamalCipher.java
create mode 100644 src/test/java/com/thealgorithms/ciphers/ElGamalCipherTest.java
diff --git a/src/main/java/com/thealgorithms/ciphers/ElGamalCipher.java b/src/main/java/com/thealgorithms/ciphers/ElGamalCipher.java
new file mode 100644
index 000000000000..6383caa59b1f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/ElGamalCipher.java
@@ -0,0 +1,174 @@
+package com.thealgorithms.ciphers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * ElGamal Encryption Algorithm Implementation.
+ *
+ *
+ * ElGamal is an asymmetric key encryption algorithm for public-key cryptography
+ * based on the Diffie–Hellman key exchange. It relies on the difficulty
+ * of computing discrete logarithms in a cyclic group.
+ *
+ *
+ *
+ * Key Features:
+ *
+ * - Uses Safe Primes (p = 2q + 1) to ensure group security.
+ * - Verifies the generator is a primitive root modulo p.
+ * - Stateless design using Java Records.
+ * - SecureRandom for all cryptographic operations.
+ *
+ *
+ *
+ * @author Chahat Sandhu, singhc7
+ * @see ElGamal Encryption (Wikipedia)
+ * @see Safe Primes
+ */
+public final class ElGamalCipher {
+
+ private static final SecureRandom RANDOM = new SecureRandom();
+ private static final int PRIME_CERTAINTY = 40;
+ private static final int MIN_BIT_LENGTH = 256;
+
+ private ElGamalCipher() {
+ }
+
+ /**
+ * A container for the Public and Private keys.
+ *
+ * @param p The prime modulus.
+ * @param g The generator (primitive root).
+ * @param y The public key component (g^x mod p).
+ * @param x The private key.
+ */
+ public record KeyPair(BigInteger p, BigInteger g, BigInteger y, BigInteger x) {
+ }
+
+ /**
+ * Container for the encryption result.
+ *
+ * @param a The first component (g^k mod p).
+ * @param b The second component (y^k * m mod p).
+ */
+ public record CipherText(BigInteger a, BigInteger b) {
+ }
+
+ /**
+ * Generates a valid ElGamal KeyPair using a Safe Prime.
+ *
+ * @param bitLength The bit length of the prime modulus p. Must be at least 256.
+ * @return A valid KeyPair (p, g, y, x).
+ * @throws IllegalArgumentException if bitLength is too small.
+ */
+ public static KeyPair generateKeys(int bitLength) {
+ if (bitLength < MIN_BIT_LENGTH) {
+ throw new IllegalArgumentException("Bit length must be at least " + MIN_BIT_LENGTH + " for security.");
+ }
+
+ BigInteger p;
+ BigInteger q;
+ BigInteger g;
+ BigInteger x;
+ BigInteger y;
+
+ // Generate Safe Prime p = 2q + 1
+ do {
+ q = new BigInteger(bitLength - 1, PRIME_CERTAINTY, RANDOM);
+ p = q.multiply(BigInteger.TWO).add(BigInteger.ONE);
+ } while (!p.isProbablePrime(PRIME_CERTAINTY));
+
+ // Find a Generator g (Primitive Root modulo p)
+ do {
+ g = new BigInteger(bitLength, RANDOM).mod(p.subtract(BigInteger.TWO)).add(BigInteger.TWO);
+ } while (!isValidGenerator(g, p, q));
+
+ // Generate Private Key x in range [2, p-2]
+ do {
+ x = new BigInteger(bitLength, RANDOM);
+ } while (x.compareTo(BigInteger.TWO) < 0 || x.compareTo(p.subtract(BigInteger.TWO)) > 0);
+
+ // Compute Public Key y = g^x mod p
+ y = g.modPow(x, p);
+
+ return new KeyPair(p, g, y, x);
+ }
+
+ /**
+ * Encrypts a message using the public key.
+ *
+ * @param message The message converted to BigInteger.
+ * @param p The prime modulus.
+ * @param g The generator.
+ * @param y The public key component.
+ * @return The CipherText pair (a, b).
+ * @throws IllegalArgumentException if inputs are null, negative, or message >= p.
+ */
+ public static CipherText encrypt(BigInteger message, BigInteger p, BigInteger g, BigInteger y) {
+ if (message == null || p == null || g == null || y == null) {
+ throw new IllegalArgumentException("Inputs cannot be null.");
+ }
+ if (message.compareTo(BigInteger.ZERO) < 0) {
+ throw new IllegalArgumentException("Message must be non-negative.");
+ }
+ if (message.compareTo(p) >= 0) {
+ throw new IllegalArgumentException("Message must be smaller than the prime modulus p.");
+ }
+
+ BigInteger k;
+ BigInteger pMinus1 = p.subtract(BigInteger.ONE);
+
+ // Select ephemeral key k such that 1 < k < p-1 and gcd(k, p-1) = 1
+ do {
+ k = new BigInteger(p.bitLength(), RANDOM);
+ } while (k.compareTo(BigInteger.ONE) <= 0 || k.compareTo(pMinus1) >= 0 || !k.gcd(pMinus1).equals(BigInteger.ONE));
+
+ BigInteger a = g.modPow(k, p);
+ BigInteger b = y.modPow(k, p).multiply(message).mod(p);
+
+ return new CipherText(a, b);
+ }
+
+ /**
+ * Decrypts a ciphertext using the private key.
+ *
+ * @param cipher The CipherText (a, b).
+ * @param x The private key.
+ * @param p The prime modulus.
+ * @return The decrypted message as BigInteger.
+ * @throws IllegalArgumentException if inputs are null.
+ */
+ public static BigInteger decrypt(CipherText cipher, BigInteger x, BigInteger p) {
+ if (cipher == null || x == null || p == null) {
+ throw new IllegalArgumentException("Inputs cannot be null.");
+ }
+
+ BigInteger a = cipher.a();
+ BigInteger b = cipher.b();
+
+ BigInteger s = a.modPow(x, p);
+ BigInteger sInverse = s.modInverse(p);
+
+ return b.multiply(sInverse).mod(p);
+ }
+
+ /**
+ * Verifies if g is a valid generator for safe prime p = 2q + 1.
+ *
+ * @param g The candidate generator.
+ * @param p The safe prime.
+ * @param q The Sophie Germain prime (p-1)/2.
+ * @return True if g is a primitive root, False otherwise.
+ */
+ private static boolean isValidGenerator(BigInteger g, BigInteger p, BigInteger q) {
+ // Fix: Must use braces {} for all if statements
+ if (g.equals(BigInteger.ONE)) {
+ return false;
+ }
+ if (g.modPow(BigInteger.TWO, p).equals(BigInteger.ONE)) {
+ return false;
+ }
+ return !g.modPow(q, p).equals(BigInteger.ONE);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/ciphers/ElGamalCipherTest.java b/src/test/java/com/thealgorithms/ciphers/ElGamalCipherTest.java
new file mode 100644
index 000000000000..63dec4846bbc
--- /dev/null
+++ b/src/test/java/com/thealgorithms/ciphers/ElGamalCipherTest.java
@@ -0,0 +1,145 @@
+package com.thealgorithms.ciphers;
+
+import java.math.BigInteger;
+import java.util.stream.Stream;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+/**
+ * Unit tests for ElGamalCipher.
+ * Includes property-based testing (homomorphism), probabilistic checks,
+ * and boundary validation.
+ */
+class ElGamalCipherTest {
+
+ private static ElGamalCipher.KeyPair sharedKeys;
+
+ @BeforeAll
+ static void setup() {
+ // Generate 256-bit keys for efficient unit testing
+ sharedKeys = ElGamalCipher.generateKeys(256);
+ }
+
+ @Test
+ @DisplayName("Test Key Generation Validity")
+ void testKeyGeneration() {
+ Assertions.assertNotNull(sharedKeys.p());
+ Assertions.assertNotNull(sharedKeys.g());
+ Assertions.assertNotNull(sharedKeys.x());
+ Assertions.assertNotNull(sharedKeys.y());
+
+ // Verify generator bounds: 1 < g < p
+ Assertions.assertTrue(sharedKeys.g().compareTo(BigInteger.ONE) > 0);
+ Assertions.assertTrue(sharedKeys.g().compareTo(sharedKeys.p()) < 0);
+
+ // Verify private key bounds: 1 < x < p-1
+ Assertions.assertTrue(sharedKeys.x().compareTo(BigInteger.ONE) > 0);
+ Assertions.assertTrue(sharedKeys.x().compareTo(sharedKeys.p().subtract(BigInteger.ONE)) < 0);
+ }
+
+ @Test
+ @DisplayName("Security Check: Probabilistic Encryption")
+ void testSemanticSecurity() {
+ // Encrypting the same message twice MUST yield different ciphertexts
+ // due to the random ephemeral key 'k'.
+ BigInteger message = new BigInteger("123456789");
+
+ ElGamalCipher.CipherText c1 = ElGamalCipher.encrypt(message, sharedKeys.p(), sharedKeys.g(), sharedKeys.y());
+ ElGamalCipher.CipherText c2 = ElGamalCipher.encrypt(message, sharedKeys.p(), sharedKeys.g(), sharedKeys.y());
+
+ // Check that the ephemeral keys (and thus 'a' components) were different
+ Assertions.assertNotEquals(c1.a(), c2.a(), "Ciphertexts must be randomized (Semantic Security violation)");
+ Assertions.assertNotEquals(c1.b(), c2.b());
+
+ // But both must decrypt to the original message
+ Assertions.assertEquals(ElGamalCipher.decrypt(c1, sharedKeys.x(), sharedKeys.p()), message);
+ Assertions.assertEquals(ElGamalCipher.decrypt(c2, sharedKeys.x(), sharedKeys.p()), message);
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideMessages")
+ @DisplayName("Parameterized Test: Encrypt and Decrypt various messages")
+ void testEncryptDecrypt(String messageStr) {
+ BigInteger message = new BigInteger(messageStr.getBytes());
+
+ // Skip if message exceeds the test key size (256 bits)
+ if (message.compareTo(sharedKeys.p()) >= 0) {
+ return;
+ }
+
+ ElGamalCipher.CipherText ciphertext = ElGamalCipher.encrypt(message, sharedKeys.p(), sharedKeys.g(), sharedKeys.y());
+ BigInteger decrypted = ElGamalCipher.decrypt(ciphertext, sharedKeys.x(), sharedKeys.p());
+
+ Assertions.assertEquals(message, decrypted, "Decrypted BigInteger must match original");
+ Assertions.assertEquals(messageStr, new String(decrypted.toByteArray()), "Decrypted string must match original");
+ }
+
+ static Stream provideMessages() {
+ return Stream.of("Hello World", "TheAlgorithms", "A", "1234567890", "!@#$%^&*()");
+ }
+
+ @Test
+ @DisplayName("Edge Case: Message equals 0")
+ void testMessageZero() {
+ BigInteger zero = BigInteger.ZERO;
+ ElGamalCipher.CipherText ciphertext = ElGamalCipher.encrypt(zero, sharedKeys.p(), sharedKeys.g(), sharedKeys.y());
+ BigInteger decrypted = ElGamalCipher.decrypt(ciphertext, sharedKeys.x(), sharedKeys.p());
+
+ Assertions.assertEquals(zero, decrypted, "Should successfully encrypt/decrypt zero");
+ }
+
+ @Test
+ @DisplayName("Edge Case: Message equals p-1")
+ void testMessageMaxBound() {
+ BigInteger pMinus1 = sharedKeys.p().subtract(BigInteger.ONE);
+ ElGamalCipher.CipherText ciphertext = ElGamalCipher.encrypt(pMinus1, sharedKeys.p(), sharedKeys.g(), sharedKeys.y());
+ BigInteger decrypted = ElGamalCipher.decrypt(ciphertext, sharedKeys.x(), sharedKeys.p());
+
+ Assertions.assertEquals(pMinus1, decrypted, "Should successfully encrypt/decrypt p-1");
+ }
+
+ @Test
+ @DisplayName("Negative Test: Message >= p should fail")
+ void testMessageTooLarge() {
+ BigInteger tooLarge = sharedKeys.p();
+ Assertions.assertThrows(IllegalArgumentException.class, () -> ElGamalCipher.encrypt(tooLarge, sharedKeys.p(), sharedKeys.g(), sharedKeys.y()));
+ }
+
+ @Test
+ @DisplayName("Negative Test: Decrypt with wrong private key")
+ void testWrongKeyDecryption() {
+ BigInteger message = new BigInteger("99999");
+ ElGamalCipher.CipherText ciphertext = ElGamalCipher.encrypt(message, sharedKeys.p(), sharedKeys.g(), sharedKeys.y());
+
+ // Generate a fake private key
+ BigInteger wrongX = sharedKeys.x().add(BigInteger.ONE);
+
+ BigInteger decrypted = ElGamalCipher.decrypt(ciphertext, wrongX, sharedKeys.p());
+
+ Assertions.assertNotEquals(message, decrypted, "Decryption with wrong key must yield incorrect result");
+ }
+
+ @Test
+ @DisplayName("Property Test: Multiplicative Homomorphism")
+ void testHomomorphism() {
+ BigInteger m1 = new BigInteger("50");
+ BigInteger m2 = BigInteger.TEN; // Fix: Replaced new BigInteger("10") with BigInteger.TEN
+
+ ElGamalCipher.CipherText c1 = ElGamalCipher.encrypt(m1, sharedKeys.p(), sharedKeys.g(), sharedKeys.y());
+ ElGamalCipher.CipherText c2 = ElGamalCipher.encrypt(m2, sharedKeys.p(), sharedKeys.g(), sharedKeys.y());
+
+ // Multiply ciphertexts component-wise: (a1*a2, b1*b2)
+ BigInteger aNew = c1.a().multiply(c2.a()).mod(sharedKeys.p());
+ BigInteger bNew = c1.b().multiply(c2.b()).mod(sharedKeys.p());
+ ElGamalCipher.CipherText cCombined = new ElGamalCipher.CipherText(aNew, bNew);
+
+ BigInteger decrypted = ElGamalCipher.decrypt(cCombined, sharedKeys.x(), sharedKeys.p());
+ BigInteger expected = m1.multiply(m2).mod(sharedKeys.p());
+
+ Assertions.assertEquals(expected, decrypted, "Cipher must satisfy multiplicative homomorphism");
+ }
+}
From 249b88fea2d8e7d425af8db053196e9b2cf1ed2c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 5 Feb 2026 23:03:26 +0100
Subject: [PATCH 26/58] chore(deps): bump com.puppycrawl.tools:checkstyle from
13.1.0 to 13.2.0 (#7259)
Bumps [com.puppycrawl.tools:checkstyle](https://github.com/checkstyle/checkstyle) from 13.1.0 to 13.2.0.
- [Release notes](https://github.com/checkstyle/checkstyle/releases)
- [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-13.1.0...checkstyle-13.2.0)
---
updated-dependencies:
- dependency-name: com.puppycrawl.tools:checkstyle
dependency-version: 13.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 f13169cece97..3716323bd115 100644
--- a/pom.xml
+++ b/pom.xml
@@ -112,7 +112,7 @@
com.puppycrawl.tools
checkstyle
- 13.1.0
+ 13.2.0
From 3835c4822a651f90be03830f778bbc41c898c64c Mon Sep 17 00:00:00 2001
From: swativ15 <122958079+swativ15@users.noreply.github.com>
Date: Fri, 6 Feb 2026 03:37:11 +0530
Subject: [PATCH 27/58] Refactor: simplify validation and improve backtracking
cleanup (#7258)
### Summary
This PR makes small readability and maintainability improvements to the algorithm implementation.
### Changes
- Removed a redundant `n < 0` validation check since the method contract already ensures valid `n`
- Replaced `current.remove(current.size() - 1)` with `current.removeLast()` to better express backtracking intent
### Rationale
- Simplifies input validation without changing behavior
- Uses the `Deque` API to make the backtracking step clearer and less error-prone
### Impact
- No change in algorithm logic or time/space complexity
- Output remains identical
Co-authored-by: Swati Vusurumarthi
---
.../com/thealgorithms/backtracking/ArrayCombination.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java
index f8cd0c40c20e..d05e33a4242f 100644
--- a/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java
+++ b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java
@@ -20,8 +20,8 @@ private ArrayCombination() {
* @throws IllegalArgumentException if n or k are negative, or if k is greater than n.
*/
public static List> combination(int n, int k) {
- if (n < 0 || k < 0 || k > n) {
- throw new IllegalArgumentException("Invalid input: n must be non-negative, k must be non-negative and less than or equal to n.");
+ if (k < 0 || k > n) {
+ throw new IllegalArgumentException("Invalid input: 0 ≤ k ≤ n is required.");
}
List> combinations = new ArrayList<>();
@@ -48,7 +48,7 @@ private static void combine(List> combinations, List curr
for (int i = start; i < n; i++) {
current.add(i);
combine(combinations, current, i + 1, n, k);
- current.remove(current.size() - 1); // Backtrack
+ current.removeLast(); // Backtrack
}
}
}
From 8403b8feb198ce250a1e2aef4416216154300961 Mon Sep 17 00:00:00 2001
From: Adarsh-Melath
Date: Mon, 9 Feb 2026 23:02:56 +0530
Subject: [PATCH 28/58] fix:shape's dimension constraints added correctyl
(issue id: #7260) (#7261)
* fix:shape's dimension constraints added correctyl (issue id: #7260)
* fix: base changed to baseLength for better understanding
* fix: base changed to baseLength for better understanding
* base changed to baseLength for better understanding
* fix:cleared some format issues
* fix:cleared some format issues
---
.../java/com/thealgorithms/maths/Area.java | 38 +++++++++----------
1 file changed, 19 insertions(+), 19 deletions(-)
diff --git a/src/main/java/com/thealgorithms/maths/Area.java b/src/main/java/com/thealgorithms/maths/Area.java
index 1eba6666dde3..08807580cb03 100644
--- a/src/main/java/com/thealgorithms/maths/Area.java
+++ b/src/main/java/com/thealgorithms/maths/Area.java
@@ -10,17 +10,17 @@ private Area() {
/**
* String of IllegalArgumentException for radius
*/
- private static final String POSITIVE_RADIUS = "Must be a positive radius";
+ private static final String POSITIVE_RADIUS = "Radius must be greater than 0";
/**
* String of IllegalArgumentException for height
*/
- private static final String POSITIVE_HEIGHT = "Must be a positive height";
+ private static final String POSITIVE_HEIGHT = "Height must be greater than 0";
/**
* String of IllegalArgumentException for base
*/
- private static final String POSITIVE_BASE = "Must be a positive base";
+ private static final String POSITIVE_BASE = "Base must be greater than 0";
/**
* Calculate the surface area of a cube.
@@ -30,7 +30,7 @@ private Area() {
*/
public static double surfaceAreaCube(final double sideLength) {
if (sideLength <= 0) {
- throw new IllegalArgumentException("Must be a positive sideLength");
+ throw new IllegalArgumentException("Side length must be greater than 0");
}
return 6 * sideLength * sideLength;
}
@@ -57,10 +57,10 @@ public static double surfaceAreaSphere(final double radius) {
*/
public static double surfaceAreaPyramid(final double sideLength, final double slantHeight) {
if (sideLength <= 0) {
- throw new IllegalArgumentException("Must be a positive sideLength");
+ throw new IllegalArgumentException("");
}
if (slantHeight <= 0) {
- throw new IllegalArgumentException("Must be a positive slantHeight");
+ throw new IllegalArgumentException("slant height must be greater than 0");
}
double baseArea = sideLength * sideLength;
double lateralSurfaceArea = 2 * sideLength * slantHeight;
@@ -76,10 +76,10 @@ public static double surfaceAreaPyramid(final double sideLength, final double sl
*/
public static double surfaceAreaRectangle(final double length, final double width) {
if (length <= 0) {
- throw new IllegalArgumentException("Must be a positive length");
+ throw new IllegalArgumentException("Length must be greater than 0");
}
if (width <= 0) {
- throw new IllegalArgumentException("Must be a positive width");
+ throw new IllegalArgumentException("Width must be greater than 0");
}
return length * width;
}
@@ -109,7 +109,7 @@ public static double surfaceAreaCylinder(final double radius, final double heigh
*/
public static double surfaceAreaSquare(final double sideLength) {
if (sideLength <= 0) {
- throw new IllegalArgumentException("Must be a positive sideLength");
+ throw new IllegalArgumentException("Side Length must be greater than 0");
}
return sideLength * sideLength;
}
@@ -121,14 +121,14 @@ public static double surfaceAreaSquare(final double sideLength) {
* @param height height of triangle
* @return area of given triangle
*/
- public static double surfaceAreaTriangle(final double base, final double height) {
- if (base <= 0) {
+ public static double surfaceAreaTriangle(final double baseLength, final double height) {
+ if (baseLength <= 0) {
throw new IllegalArgumentException(POSITIVE_BASE);
}
if (height <= 0) {
throw new IllegalArgumentException(POSITIVE_HEIGHT);
}
- return base * height / 2;
+ return baseLength * height / 2;
}
/**
@@ -138,14 +138,14 @@ public static double surfaceAreaTriangle(final double base, final double height)
* @param height height of a parallelogram
* @return area of given parallelogram
*/
- public static double surfaceAreaParallelogram(final double base, final double height) {
- if (base <= 0) {
+ public static double surfaceAreaParallelogram(final double baseLength, final double height) {
+ if (baseLength <= 0) {
throw new IllegalArgumentException(POSITIVE_BASE);
}
if (height <= 0) {
throw new IllegalArgumentException(POSITIVE_HEIGHT);
}
- return base * height;
+ return baseLength * height;
}
/**
@@ -156,17 +156,17 @@ public static double surfaceAreaParallelogram(final double base, final double he
* @param height height of trapezium
* @return area of given trapezium
*/
- public static double surfaceAreaTrapezium(final double base1, final double base2, final double height) {
- if (base1 <= 0) {
+ public static double surfaceAreaTrapezium(final double baseLength1, final double baseLength2, final double height) {
+ if (baseLength1 <= 0) {
throw new IllegalArgumentException(POSITIVE_BASE + 1);
}
- if (base2 <= 0) {
+ if (baseLength2 <= 0) {
throw new IllegalArgumentException(POSITIVE_BASE + 2);
}
if (height <= 0) {
throw new IllegalArgumentException(POSITIVE_HEIGHT);
}
- return (base1 + base2) * height / 2;
+ return (baseLength1 + baseLength2) * height / 2;
}
/**
From 0c79d33eb591842c8cc809f02a9303ab843a1c37 Mon Sep 17 00:00:00 2001
From: Mohammed Vijahath <116938255+vizahat36@users.noreply.github.com>
Date: Wed, 11 Feb 2026 20:30:15 +0530
Subject: [PATCH 29/58] Add Tower of Hanoi recursive algorithm (#7235)
* Add Tower of Hanoi recursive algorithm with tests
* Fix SpotBugs issues and format TowerOfHanoi tests
* Enhance existing TowerOfHanoi and remove duplicate recursion version
* Fix clang-format issue
---------
Co-authored-by: Deniz Altunkapan
---
.../puzzlesandgames/TowerOfHanoi.java | 51 +++++++++++--------
.../puzzlesandgames/TowerOfHanoiTest.java | 32 ++++++++++++
2 files changed, 63 insertions(+), 20 deletions(-)
diff --git a/src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java b/src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java
index 72e9a14ac070..d94bef69cd3a 100644
--- a/src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java
+++ b/src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java
@@ -3,27 +3,32 @@
import java.util.List;
/**
- * The {@code TowerOfHanoi} class provides a recursive solution to the Tower of Hanoi puzzle.
- * This puzzle involves moving a set of discs from one pole to another, following specific rules:
+ * Recursive solution to the Tower of Hanoi puzzle.
+ *
+ *
+ * The puzzle rules are:
* 1. Only one disc can be moved at a time.
* 2. A disc can only be placed on top of a larger disc.
* 3. All discs must start on one pole and end on another.
+ *
*
- * This implementation recursively calculates the steps required to solve the puzzle and stores them
- * in a provided list.
+ *
+ * The recursion follows three steps:
+ * 1. Move {@code n-1} discs from start to intermediate.
+ * 2. Move the largest disc from start to end.
+ * 3. Move {@code n-1} discs from intermediate to end.
+ *
*
*
- * For more information about the Tower of Hanoi, see
- * Tower of Hanoi on Wikipedia.
+ * Time Complexity: O(2^n) - exponential due to recursive expansion.
+ * Space Complexity: O(n) - recursion stack depth.
*
*
- * The {@code shift} method takes the number of discs and the names of the poles,
- * and appends the steps required to solve the puzzle to the provided list.
- * Time Complexity: O(2^n) - Exponential time complexity due to the recursive nature of the problem.
- * Space Complexity: O(n) - Linear space complexity due to the recursion stack.
- * Wikipedia: https://en.wikipedia.org/wiki/Tower_of_Hanoi
+ *
+ * See Tower of Hanoi on Wikipedia.
+ *
*/
-final class TowerOfHanoi {
+public final class TowerOfHanoi {
private TowerOfHanoi() {
}
@@ -36,6 +41,7 @@ private TowerOfHanoi() {
* @param intermediatePole The name of the intermediate pole used as a temporary holding area.
* @param endPole The name of the end pole to which discs are moved.
* @param result A list to store the steps required to solve the puzzle.
+ * @throws IllegalArgumentException if {@code n} is negative.
*
*
* This method is called recursively to move n-1 discs
@@ -51,15 +57,20 @@ private TowerOfHanoi() {
*
*/
public static void shift(int n, String startPole, String intermediatePole, String endPole, List result) {
- if (n != 0) {
- // Move n-1 discs from startPole to intermediatePole
- shift(n - 1, startPole, endPole, intermediatePole, result);
+ if (n < 0) {
+ throw new IllegalArgumentException("Number of discs must be non-negative");
+ }
+ if (n == 0) {
+ return;
+ }
- // Add the move of the nth disc from startPole to endPole
- result.add(String.format("Move %d from %s to %s", n, startPole, endPole));
+ // Move n-1 discs from startPole to intermediatePole
+ shift(n - 1, startPole, endPole, intermediatePole, result);
- // Move the n-1 discs from intermediatePole to endPole
- shift(n - 1, intermediatePole, startPole, endPole, result);
- }
+ // Add the move of the nth disc from startPole to endPole
+ result.add(String.format("Move %d from %s to %s", n, startPole, endPole));
+
+ // Move the n-1 discs from intermediatePole to endPole
+ shift(n - 1, intermediatePole, startPole, endPole, result);
}
}
diff --git a/src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java b/src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java
index 42669eb03bb4..f0a2686d3e4b 100644
--- a/src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java
+++ b/src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java
@@ -1,14 +1,31 @@
package com.thealgorithms.puzzlesandgames;
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.ArrayList;
import java.util.List;
+import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
public class TowerOfHanoiTest {
+ @ParameterizedTest
+ @MethodSource("diskCountAndMoveCount")
+ void testMoveCountMatchesFormula(int disks, int expectedMoves) {
+ List result = new ArrayList<>();
+ TowerOfHanoi.shift(disks, "A", "B", "C", result);
+ assertEquals(expectedMoves, result.size());
+ }
+
+ private static Stream diskCountAndMoveCount() {
+ return Stream.of(Arguments.of(1, 1), Arguments.of(2, 3), Arguments.of(3, 7), Arguments.of(4, 15), Arguments.of(5, 31), Arguments.of(10, 1023));
+ }
+
@Test
public void testHanoiWithOneDisc() {
List result = new ArrayList<>();
@@ -39,6 +56,15 @@ public void testHanoiWithThreeDiscs() {
assertEquals(expected, result);
}
+ @Test
+ public void testHanoiWithDifferentPoles() {
+ List result = new ArrayList<>();
+ TowerOfHanoi.shift(2, "X", "Y", "Z", result);
+
+ List expected = List.of("Move 1 from X to Y", "Move 2 from X to Z", "Move 1 from Y to Z");
+ assertEquals(expected, result);
+ }
+
@Test
public void testHanoiWithZeroDiscs() {
List result = new ArrayList<>();
@@ -47,4 +73,10 @@ public void testHanoiWithZeroDiscs() {
// There should be no moves if there are 0 discs
assertTrue(result.isEmpty());
}
+
+ @Test
+ public void testHanoiWithNegativeDiscsThrows() {
+ List result = new ArrayList<>();
+ assertThrows(IllegalArgumentException.class, () -> TowerOfHanoi.shift(-1, "Pole1", "Pole2", "Pole3", result));
+ }
}
From 504b5283eb75f9416693740eba48c5cea9eb28bd Mon Sep 17 00:00:00 2001
From: Muhammad Muneeb Mubashar
Date: Fri, 13 Feb 2026 01:43:27 -0800
Subject: [PATCH 30/58] Refactor getAbsValue method to use Math.abs (#7266)
---
src/main/java/com/thealgorithms/maths/AbsoluteValue.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/maths/AbsoluteValue.java b/src/main/java/com/thealgorithms/maths/AbsoluteValue.java
index b9279d5a244a..114eb71b1015 100644
--- a/src/main/java/com/thealgorithms/maths/AbsoluteValue.java
+++ b/src/main/java/com/thealgorithms/maths/AbsoluteValue.java
@@ -11,6 +11,6 @@ private AbsoluteValue() {
* @return The absolute value of the {@code number}
*/
public static int getAbsValue(int number) {
- return number < 0 ? -number : number;
+ return Math.abs(number);
}
}
From c8d029107ce397c6d427a23a5127003d87fb0792 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 16 Feb 2026 16:57:18 +0100
Subject: [PATCH 31/58] chore(deps): bump org.junit:junit-bom from 6.0.2 to
6.0.3 (#7271)
Bumps [org.junit:junit-bom](https://github.com/junit-team/junit-framework) from 6.0.2 to 6.0.3.
- [Release notes](https://github.com/junit-team/junit-framework/releases)
- [Commits](https://github.com/junit-team/junit-framework/compare/r6.0.2...r6.0.3)
---
updated-dependencies:
- dependency-name: org.junit:junit-bom
dependency-version: 6.0.3
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 3716323bd115..2445a1e920a8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,7 +20,7 @@
org.junit
junit-bom
- 6.0.2
+ 6.0.3
pom
import
From dfa6bf06910b2c989a0e4acb82155ebf51d869f9 Mon Sep 17 00:00:00 2001
From: Piotr Idzik <65706193+vil02@users.noreply.github.com>
Date: Tue, 17 Feb 2026 22:20:34 +0100
Subject: [PATCH 32/58] style: remove redundant PMD exclusions (#7272)
---
pmd-exclude.properties | 11 -----------
1 file changed, 11 deletions(-)
diff --git a/pmd-exclude.properties b/pmd-exclude.properties
index a3c95b12fa4b..64562c524728 100644
--- a/pmd-exclude.properties
+++ b/pmd-exclude.properties
@@ -53,14 +53,11 @@ com.thealgorithms.maths.Gaussian=UselessParentheses
com.thealgorithms.maths.GcdSolutionWrapper=UselessParentheses
com.thealgorithms.maths.HeronsFormula=UselessParentheses
com.thealgorithms.maths.JugglerSequence=UselessMainMethod
-com.thealgorithms.maths.KaprekarNumbers=UselessParentheses
com.thealgorithms.maths.KeithNumber=UselessMainMethod,UselessParentheses
-com.thealgorithms.maths.LeonardoNumber=UselessParentheses
com.thealgorithms.maths.LinearDiophantineEquationsSolver=UselessMainMethod,UselessParentheses
com.thealgorithms.maths.MagicSquare=UselessMainMethod
com.thealgorithms.maths.PiNilakantha=UselessMainMethod
com.thealgorithms.maths.Prime.PrimeCheck=UselessMainMethod
-com.thealgorithms.maths.PythagoreanTriple=UselessMainMethod
com.thealgorithms.maths.RomanNumeralUtil=UselessParentheses
com.thealgorithms.maths.SecondMinMax=UselessParentheses
com.thealgorithms.maths.SecondMinMaxTest=UnnecessaryFullyQualifiedName
@@ -71,7 +68,6 @@ com.thealgorithms.maths.TrinomialTriangle=UselessMainMethod,UselessParentheses
com.thealgorithms.maths.VectorCrossProduct=UselessMainMethod
com.thealgorithms.maths.Volume=UselessParentheses
com.thealgorithms.matrix.RotateMatrixBy90Degrees=UselessMainMethod
-com.thealgorithms.misc.Sparsity=UselessParentheses
com.thealgorithms.others.BankersAlgorithm=UselessMainMethod
com.thealgorithms.others.BrianKernighanAlgorithm=UselessMainMethod
com.thealgorithms.others.CRC16=UselessMainMethod,UselessParentheses
@@ -79,11 +75,9 @@ com.thealgorithms.others.CRC32=UselessMainMethod
com.thealgorithms.others.Damm=UnnecessaryFullyQualifiedName,UselessMainMethod
com.thealgorithms.others.Dijkstra=UselessMainMethod
com.thealgorithms.others.GaussLegendre=UselessMainMethod
-com.thealgorithms.others.HappyNumbersSeq=UselessMainMethod
com.thealgorithms.others.Huffman=UselessMainMethod
com.thealgorithms.others.InsertDeleteInArray=UselessMainMethod
com.thealgorithms.others.KochSnowflake=UselessMainMethod
-com.thealgorithms.others.Krishnamurthy=UselessMainMethod
com.thealgorithms.others.LinearCongruentialGenerator=UselessMainMethod
com.thealgorithms.others.Luhn=UnnecessaryFullyQualifiedName,UselessMainMethod
com.thealgorithms.others.Mandelbrot=UselessMainMethod,UselessParentheses
@@ -94,7 +88,6 @@ com.thealgorithms.others.PerlinNoise=UselessMainMethod,UselessParentheses
com.thealgorithms.others.QueueUsingTwoStacks=UselessParentheses
com.thealgorithms.others.Trieac=UselessMainMethod,UselessParentheses
com.thealgorithms.others.Verhoeff=UnnecessaryFullyQualifiedName,UselessMainMethod
-com.thealgorithms.puzzlesandgames.Sudoku=UselessMainMethod
com.thealgorithms.recursion.DiceThrower=UselessMainMethod
com.thealgorithms.searches.HowManyTimesRotated=UselessMainMethod
com.thealgorithms.searches.InterpolationSearch=UselessParentheses
@@ -108,15 +101,11 @@ com.thealgorithms.sorts.MergeSortNoExtraSpace=UselessParentheses
com.thealgorithms.sorts.RadixSort=UselessParentheses
com.thealgorithms.sorts.TreeSort=UselessMainMethod
com.thealgorithms.sorts.WiggleSort=UselessParentheses
-com.thealgorithms.stacks.LargestRectangle=UselessMainMethod
com.thealgorithms.stacks.MaximumMinimumWindow=UselessMainMethod
com.thealgorithms.stacks.PostfixToInfix=UselessParentheses
-com.thealgorithms.strings.Alphabetical=UselessMainMethod
com.thealgorithms.strings.HorspoolSearch=UnnecessaryFullyQualifiedName,UselessParentheses
-com.thealgorithms.strings.KMP=UselessMainMethod
com.thealgorithms.strings.Lower=UselessMainMethod
com.thealgorithms.strings.Palindrome=UselessParentheses
com.thealgorithms.strings.Pangram=UselessMainMethod
-com.thealgorithms.strings.RabinKarp=UselessMainMethod
com.thealgorithms.strings.Rotation=UselessMainMethod
com.thealgorithms.strings.Upper=UselessMainMethod
From 1646edaeb96a27add8d83788782550ee2048b263 Mon Sep 17 00:00:00 2001
From: Piotr Idzik <65706193+vil02@users.noreply.github.com>
Date: Wed, 18 Feb 2026 18:06:08 +0100
Subject: [PATCH 33/58] style: remove redundant exclusions (#7276)
---
spotbugs-exclude.xml | 39 ---------------------------------------
1 file changed, 39 deletions(-)
diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml
index 1390387bacdf..7483d37daa57 100644
--- a/spotbugs-exclude.xml
+++ b/spotbugs-exclude.xml
@@ -8,18 +8,12 @@
-
-
-
-
-
-
@@ -32,15 +26,9 @@
-
-
-
-
-
-
@@ -50,15 +38,9 @@
-
-
-
-
-
-
@@ -71,9 +53,6 @@
-
-
-
@@ -83,9 +62,6 @@
-
-
-
@@ -117,9 +93,6 @@
-
-
-
@@ -150,9 +123,6 @@
-
-
-
@@ -189,24 +159,15 @@
-
-
-
-
-
-
-
-
-
From c9bda3dad761c5b27edc36e32b8b9c746ebda345 Mon Sep 17 00:00:00 2001
From: Syed Mohammad Saad <134770714+SYEDMDSAAD@users.noreply.github.com>
Date: Wed, 18 Feb 2026 23:54:34 +0530
Subject: [PATCH 34/58] Add string algorithms: RemoveStars and
ComplexNumberMultiply (#7275)
* Add RemoveStars and ComplexNumberMultiply string algorithms
* Add RemoveStars and ComplexNumberMultiply string algorithms
* Add unit tests for RemoveStars and ComplexNumber Multiply
* Fix checkstyle
* Remove redundant main method
* Move ComplexNumberMultiply to maths package and add input validation with tests
* Apply spotless formatting
---------
Co-authored-by: Deniz Altunkapan
---
.../maths/ComplexNumberMultiply.java | 32 +++++++++++++++++
.../thealgorithms/strings/RemoveStars.java | 31 +++++++++++++++++
.../maths/ComplexNumberMultiplyTest.java | 34 +++++++++++++++++++
.../strings/RemoveStarsTest.java | 28 +++++++++++++++
4 files changed, 125 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/maths/ComplexNumberMultiply.java
create mode 100644 src/main/java/com/thealgorithms/strings/RemoveStars.java
create mode 100644 src/test/java/com/thealgorithms/maths/ComplexNumberMultiplyTest.java
create mode 100644 src/test/java/com/thealgorithms/strings/RemoveStarsTest.java
diff --git a/src/main/java/com/thealgorithms/maths/ComplexNumberMultiply.java b/src/main/java/com/thealgorithms/maths/ComplexNumberMultiply.java
new file mode 100644
index 000000000000..4b68b7824574
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/ComplexNumberMultiply.java
@@ -0,0 +1,32 @@
+package com.thealgorithms.maths;
+
+/**
+ * Multiplies two complex numbers represented as strings in the form "a+bi".
+ * Supports negative values and validates input format.
+ */
+public final class ComplexNumberMultiply {
+
+ private ComplexNumberMultiply() {
+ }
+
+ private static int[] parse(String num) {
+ if (num == null || !num.matches("-?\\d+\\+-?\\d+i")) {
+ throw new IllegalArgumentException("Invalid complex number format: " + num);
+ }
+
+ String[] parts = num.split("\\+");
+ int real = Integer.parseInt(parts[0]);
+ int imaginary = Integer.parseInt(parts[1].replace("i", ""));
+ return new int[] {real, imaginary};
+ }
+
+ public static String multiply(String num1, String num2) {
+ int[] a = parse(num1);
+ int[] b = parse(num2);
+
+ int real = a[0] * b[0] - a[1] * b[1];
+ int imaginary = a[0] * b[1] + a[1] * b[0];
+
+ return real + "+" + imaginary + "i";
+ }
+}
diff --git a/src/main/java/com/thealgorithms/strings/RemoveStars.java b/src/main/java/com/thealgorithms/strings/RemoveStars.java
new file mode 100644
index 000000000000..816311e9da84
--- /dev/null
+++ b/src/main/java/com/thealgorithms/strings/RemoveStars.java
@@ -0,0 +1,31 @@
+package com.thealgorithms.strings;
+
+/**
+ * Removes characters affected by '*' in a string.
+ * Each '*' deletes the closest non-star character to its left.
+ *
+ * Example:
+ * Input: leet**cod*e
+ * Output: lecoe
+ */
+
+public final class RemoveStars {
+
+ private RemoveStars() {
+ }
+
+ public static String removeStars(String s) {
+ StringBuilder result = new StringBuilder();
+
+ for (char c : s.toCharArray()) {
+ if (c == '*') {
+ if (result.length() > 0) {
+ result.deleteCharAt(result.length() - 1);
+ }
+ } else {
+ result.append(c);
+ }
+ }
+ return result.toString();
+ }
+}
diff --git a/src/test/java/com/thealgorithms/maths/ComplexNumberMultiplyTest.java b/src/test/java/com/thealgorithms/maths/ComplexNumberMultiplyTest.java
new file mode 100644
index 000000000000..02e964b53771
--- /dev/null
+++ b/src/test/java/com/thealgorithms/maths/ComplexNumberMultiplyTest.java
@@ -0,0 +1,34 @@
+package com.thealgorithms.maths;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class ComplexNumberMultiplyTest {
+
+ @Test
+ void testExample() {
+ assertEquals("0+2i", ComplexNumberMultiply.multiply("1+1i", "1+1i"));
+ }
+
+ @Test
+ void testNegative() {
+ assertEquals("0+-2i", ComplexNumberMultiply.multiply("1+-1i", "1+-1i"));
+ }
+
+ @Test
+ void testZero() {
+ assertEquals("0+0i", ComplexNumberMultiply.multiply("0+0i", "5+3i"));
+ }
+
+ @Test
+ void testInvalidFormat() {
+ assertThrows(IllegalArgumentException.class, () -> ComplexNumberMultiply.multiply("1+1", "1+1i"));
+ }
+
+ @Test
+ void testNullInput() {
+ assertThrows(IllegalArgumentException.class, () -> ComplexNumberMultiply.multiply(null, "1+1i"));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/strings/RemoveStarsTest.java b/src/test/java/com/thealgorithms/strings/RemoveStarsTest.java
new file mode 100644
index 000000000000..3beb2e83399b
--- /dev/null
+++ b/src/test/java/com/thealgorithms/strings/RemoveStarsTest.java
@@ -0,0 +1,28 @@
+package com.thealgorithms.strings;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class RemoveStarsTest {
+
+ @Test
+ void testExampleCase() {
+ assertEquals("lecoe", RemoveStars.removeStars("leet**cod*e"));
+ }
+
+ @Test
+ void testAllStars() {
+ assertEquals("", RemoveStars.removeStars("abc***"));
+ }
+
+ @Test
+ void testNoStars() {
+ assertEquals("hello", RemoveStars.removeStars("hello"));
+ }
+
+ @Test
+ void testSingleCharacter() {
+ assertEquals("", RemoveStars.removeStars("a*"));
+ }
+}
From 2ae1bdfd9a3897d206c0e62751b7ec562dcafb08 Mon Sep 17 00:00:00 2001
From: Neha-2005-VCE
Date: Thu, 19 Feb 2026 00:04:41 +0530
Subject: [PATCH 35/58] feat: add contains() method to DynamicArray (#7270)
* feat: add contains() method to DynamicArray
* style: fix clang formatting
* style: fix clang format issues
* style: apply remaining clang formatting
---------
Co-authored-by: Deniz Altunkapan
---
.../dynamicarray/DynamicArray.java | 43 +++++++++++++++----
.../dynamicarray/DynamicArrayTest.java | 19 ++++++++
2 files changed, 53 insertions(+), 9 deletions(-)
diff --git a/src/main/java/com/thealgorithms/datastructures/dynamicarray/DynamicArray.java b/src/main/java/com/thealgorithms/datastructures/dynamicarray/DynamicArray.java
index cd5dc580b694..dbdb2d806209 100644
--- a/src/main/java/com/thealgorithms/datastructures/dynamicarray/DynamicArray.java
+++ b/src/main/java/com/thealgorithms/datastructures/dynamicarray/DynamicArray.java
@@ -63,7 +63,8 @@ public void add(final E element) {
*
* @param index the index at which the element is to be placed
* @param element the element to be inserted at the specified index
- * @throws IndexOutOfBoundsException if index is less than 0 or greater than or equal to the number of elements
+ * @throws IndexOutOfBoundsException if index is less than 0 or greater than or
+ * equal to the number of elements
*/
public void put(final int index, E element) {
if (index < 0) {
@@ -82,7 +83,8 @@ public void put(final int index, E element) {
*
* @param index the index of the element to retrieve
* @return the element at the specified index
- * @throws IndexOutOfBoundsException if index is less than 0 or greater than or equal to the current size
+ * @throws IndexOutOfBoundsException if index is less than 0 or greater than or
+ * equal to the current size
*/
@SuppressWarnings("unchecked")
public E get(final int index) {
@@ -97,7 +99,8 @@ public E get(final int index) {
*
* @param index the index of the element to be removed
* @return the element that was removed from the array
- * @throws IndexOutOfBoundsException if index is less than 0 or greater than or equal to the current size
+ * @throws IndexOutOfBoundsException if index is less than 0 or greater than or
+ * equal to the current size
*/
public E remove(final int index) {
if (index < 0 || index >= size) {
@@ -127,6 +130,21 @@ public boolean isEmpty() {
return size == 0;
}
+ /**
+ * Checks whether the array contains the specified element.
+ *
+ * @param element the element to check for
+ * @return true if the array contains the specified element, false otherwise
+ */
+ public boolean contains(final E element) {
+ for (int i = 0; i < size; i++) {
+ if (Objects.equals(elements[i], element)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Returns a sequential stream with this collection as its source.
*
@@ -137,7 +155,8 @@ public Stream stream() {
}
/**
- * Ensures that the array has enough capacity to hold the specified number of elements.
+ * Ensures that the array has enough capacity to hold the specified number of
+ * elements.
*
* @param minCapacity the minimum capacity required
*/
@@ -150,7 +169,8 @@ private void ensureCapacity(int minCapacity) {
/**
* Removes the element at the specified index without resizing the array.
- * This method shifts any subsequent elements to the left and clears the last element.
+ * This method shifts any subsequent elements to the left and clears the last
+ * element.
*
* @param index the index of the element to remove
*/
@@ -163,7 +183,8 @@ private void fastRemove(int index) {
}
/**
- * Returns a string representation of the array, including only the elements that are currently stored.
+ * Returns a string representation of the array, including only the elements
+ * that are currently stored.
*
* @return a string containing the elements in the array
*/
@@ -227,7 +248,9 @@ public E next() {
/**
* Removes the last element returned by this iterator.
*
- * @throws IllegalStateException if the next method has not yet been called, or the remove method has already been called after the last call to the next method
+ * @throws IllegalStateException if the next method has not yet been called, or
+ * the remove method has already been called after
+ * the last call to the next method
*/
@Override
public void remove() {
@@ -242,7 +265,8 @@ public void remove() {
/**
* Checks for concurrent modifications to the array during iteration.
*
- * @throws ConcurrentModificationException if the array has been modified structurally
+ * @throws ConcurrentModificationException if the array has been modified
+ * structurally
*/
private void checkForComodification() {
if (modCount != expectedModCount) {
@@ -251,7 +275,8 @@ private void checkForComodification() {
}
/**
- * Performs the given action for each remaining element in the iterator until all elements have been processed.
+ * Performs the given action for each remaining element in the iterator until
+ * all elements have been processed.
*
* @param action the action to be performed for each element
* @throws NullPointerException if the specified action is null
diff --git a/src/test/java/com/thealgorithms/datastructures/dynamicarray/DynamicArrayTest.java b/src/test/java/com/thealgorithms/datastructures/dynamicarray/DynamicArrayTest.java
index 8fdc93e1ca22..39e3fa0abe77 100644
--- a/src/test/java/com/thealgorithms/datastructures/dynamicarray/DynamicArrayTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/dynamicarray/DynamicArrayTest.java
@@ -255,4 +255,23 @@ public void testCapacityDoubling() {
assertEquals(3, array.getSize());
assertEquals("Charlie", array.get(2));
}
+
+ @Test
+ public void testContains() {
+ DynamicArray array = new DynamicArray<>();
+ array.add(1);
+ array.add(2);
+ array.add(3);
+
+ assertTrue(array.contains(2));
+ assertFalse(array.contains(5));
+ }
+
+ @Test
+ public void testContainsWithNull() {
+ DynamicArray array = new DynamicArray<>();
+ array.add(null);
+
+ assertTrue(array.contains(null));
+ }
}
From 0a2c7f2e3bb539d3aee68673b5d743d178d455b2 Mon Sep 17 00:00:00 2001
From: Piotr Idzik <65706193+vil02@users.noreply.github.com>
Date: Wed, 18 Feb 2026 20:32:32 +0100
Subject: [PATCH 36/58] style: include `BL_BURYING_LOGIC` (#7277)
---
spotbugs-exclude.xml | 3 --
.../searches/RecursiveBinarySearch.java | 33 +++++++++----------
2 files changed, 16 insertions(+), 20 deletions(-)
diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml
index 7483d37daa57..a8eedcfed402 100644
--- a/spotbugs-exclude.xml
+++ b/spotbugs-exclude.xml
@@ -90,9 +90,6 @@
-
-
-
diff --git a/src/main/java/com/thealgorithms/searches/RecursiveBinarySearch.java b/src/main/java/com/thealgorithms/searches/RecursiveBinarySearch.java
index daf0c12c0978..1716e78964ae 100644
--- a/src/main/java/com/thealgorithms/searches/RecursiveBinarySearch.java
+++ b/src/main/java/com/thealgorithms/searches/RecursiveBinarySearch.java
@@ -23,28 +23,27 @@ public int find(T[] arr, T target) {
// Recursive binary search function
public int binsear(T[] arr, int left, int right, T target) {
- if (right >= left) {
- int mid = left + (right - left) / 2;
-
- // Compare the element at the middle with the target
- int comparison = arr[mid].compareTo(target);
+ if (right < left) {
+ // Element is not present in the array
+ return -1;
+ }
+ final int mid = left + (right - left) / 2;
- // If the element is equal to the target, return its index
- if (comparison == 0) {
- return mid;
- }
+ // Compare the element at the middle with the target
+ final int comparison = arr[mid].compareTo(target);
- // If the element is greater than the target, search in the left subarray
- if (comparison > 0) {
- return binsear(arr, left, mid - 1, target);
- }
+ // If the element is equal to the target, return its index
+ if (comparison == 0) {
+ return mid;
+ }
- // Otherwise, search in the right subarray
- return binsear(arr, mid + 1, right, target);
+ // If the element is greater than the target, search in the left subarray
+ if (comparison > 0) {
+ return binsear(arr, left, mid - 1, target);
}
- // Element is not present in the array
- return -1;
+ // Otherwise, search in the right subarray
+ return binsear(arr, mid + 1, right, target);
}
public static void main(String[] args) {
From 29ce2ef66607083e922b389650af160b7606903a Mon Sep 17 00:00:00 2001
From: Ruturaj Jadhav
Date: Fri, 20 Feb 2026 02:41:56 +0530
Subject: [PATCH 37/58] Add RangeSumQuery algorithm in prefix folder (#7280)
* add Subarray Sum Equals K using prefix sum
* Add RangeSumQuery algorithm in prefix folder
* chore: apply clang-format to RangeSumQueryTest file
* Add import statement for JUnit test class
---------
Co-authored-by: Deniz Altunkapan
---
.../prefixsum/RangeSumQuery.java | 73 +++++++++++++++++++
.../prefixsum/RangeSumQueryTest.java | 73 +++++++++++++++++++
2 files changed, 146 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/prefixsum/RangeSumQuery.java
create mode 100644 src/test/java/com/thealgorithms/prefixsum/RangeSumQueryTest.java
diff --git a/src/main/java/com/thealgorithms/prefixsum/RangeSumQuery.java b/src/main/java/com/thealgorithms/prefixsum/RangeSumQuery.java
new file mode 100644
index 000000000000..14a02a2de4d0
--- /dev/null
+++ b/src/main/java/com/thealgorithms/prefixsum/RangeSumQuery.java
@@ -0,0 +1,73 @@
+package com.thealgorithms.prefixsum;
+
+/**
+ * Implements an algorithm to efficiently compute the sum of elements
+ * between any two indices in an integer array using the Prefix Sum technique.
+ *
+ *
+ * Given an array nums, this algorithm precomputes the prefix sum array
+ * to allow O(1) sum queries for any range [left, right].
+ *
+ *
+ *
+ * Let prefixSum[i] be the sum of elements from index 0 to i-1.
+ * The sum of elements from left to right is:
+ *
+ *
+ * prefixSum[right + 1] - prefixSum[left]
+ *
+ *
+ *
+ *
+ * Time Complexity: O(N) for preprocessing, O(1) per query
+ * Space Complexity: O(N)
+ *
+ *
+ * @author Ruturaj Jadhav, ruturajjadhav07
+ */
+public final class RangeSumQuery {
+
+ private RangeSumQuery() {
+ // Utility class; prevent instantiation
+ }
+
+ /**
+ * Computes the prefix sum array for efficient range queries.
+ *
+ * @param nums The input integer array.
+ * @return Prefix sum array where prefixSum[i+1] = sum of nums[0..i].
+ * @throws IllegalArgumentException if nums is null.
+ */
+ public static int[] buildPrefixSum(int[] nums) {
+ if (nums == null) {
+ throw new IllegalArgumentException("Input array cannot be null");
+ }
+
+ int n = nums.length;
+ int[] prefixSum = new int[n + 1];
+ for (int i = 0; i < n; i++) {
+ prefixSum[i + 1] = prefixSum[i] + nums[i];
+ }
+ return prefixSum;
+ }
+
+ /**
+ * Returns the sum of elements from index left to right (inclusive)
+ * using the provided prefix sum array.
+ *
+ * @param prefixSum The prefix sum array computed using buildPrefixSum.
+ * @param left The start index (inclusive).
+ * @param right The end index (inclusive).
+ * @return The sum of elements in the range [left, right].
+ * @throws IllegalArgumentException if indices are invalid.
+ */
+ public static int sumRange(int[] prefixSum, int left, int right) {
+ if (prefixSum == null) {
+ throw new IllegalArgumentException("Prefix sum array cannot be null");
+ }
+ if (left < 0 || right >= prefixSum.length - 1 || left > right) {
+ throw new IllegalArgumentException("Invalid range indices");
+ }
+ return prefixSum[right + 1] - prefixSum[left];
+ }
+}
diff --git a/src/test/java/com/thealgorithms/prefixsum/RangeSumQueryTest.java b/src/test/java/com/thealgorithms/prefixsum/RangeSumQueryTest.java
new file mode 100644
index 000000000000..12072318ac74
--- /dev/null
+++ b/src/test/java/com/thealgorithms/prefixsum/RangeSumQueryTest.java
@@ -0,0 +1,73 @@
+package com.thealgorithms.prefixsum;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for {@link RangeSumQuery}.
+ */
+class RangeSumQueryTest {
+
+ @Test
+ void testBasicExample() {
+ int[] nums = {1, 2, 3, 4, 5};
+ int[] prefixSum = RangeSumQuery.buildPrefixSum(nums);
+
+ assertEquals(6, RangeSumQuery.sumRange(prefixSum, 0, 2)); // 1+2+3
+ assertEquals(9, RangeSumQuery.sumRange(prefixSum, 1, 3)); // 2+3+4
+ assertEquals(15, RangeSumQuery.sumRange(prefixSum, 0, 4)); // 1+2+3+4+5
+ assertEquals(12, RangeSumQuery.sumRange(prefixSum, 2, 4)); // 3+4+5
+ }
+
+ @Test
+ void testSingleElement() {
+ int[] nums = {7};
+ int[] prefixSum = RangeSumQuery.buildPrefixSum(nums);
+
+ assertEquals(7, RangeSumQuery.sumRange(prefixSum, 0, 0));
+ }
+
+ @Test
+ void testAllZeros() {
+ int[] nums = {0, 0, 0, 0};
+ int[] prefixSum = RangeSumQuery.buildPrefixSum(nums);
+
+ assertEquals(0, RangeSumQuery.sumRange(prefixSum, 0, 3));
+ assertEquals(0, RangeSumQuery.sumRange(prefixSum, 1, 2));
+ }
+
+ @Test
+ void testNegativeNumbers() {
+ int[] nums = {-1, 2, -3, 4};
+ int[] prefixSum = RangeSumQuery.buildPrefixSum(nums);
+
+ assertEquals(-2, RangeSumQuery.sumRange(prefixSum, 0, 2)); // -1+2-3
+ assertEquals(3, RangeSumQuery.sumRange(prefixSum, 1, 3)); // 2-3+4
+ }
+
+ @Test
+ void testEmptyArrayThrowsException() {
+ int[] nums = {};
+ int[] prefixSum = RangeSumQuery.buildPrefixSum(nums);
+
+ assertThrows(IllegalArgumentException.class, () -> RangeSumQuery.sumRange(prefixSum, 0, 0));
+ }
+
+ @Test
+ void testNullArrayThrowsException() {
+ assertThrows(IllegalArgumentException.class, () -> RangeSumQuery.buildPrefixSum(null));
+ assertThrows(IllegalArgumentException.class, () -> RangeSumQuery.sumRange(null, 0, 0));
+ }
+
+ @Test
+ void testInvalidIndicesThrowsException() {
+ int[] nums = {1, 2, 3};
+ int[] prefixSum = RangeSumQuery.buildPrefixSum(nums);
+
+ assertThrows(IllegalArgumentException.class, () -> RangeSumQuery.sumRange(prefixSum, -1, 2));
+ assertThrows(IllegalArgumentException.class, () -> RangeSumQuery.sumRange(prefixSum, 1, 5));
+ assertThrows(IllegalArgumentException.class, () -> RangeSumQuery.sumRange(prefixSum, 2, 1));
+ }
+}
From 7c38e5acd29a22e29c6954ae7088889a4afde689 Mon Sep 17 00:00:00 2001
From: Piotr Idzik <65706193+vil02@users.noreply.github.com>
Date: Fri, 20 Feb 2026 20:48:12 +0100
Subject: [PATCH 38/58] style: include `DM_NEXTINT_VIA_NEXTDOUBLE` (#7282)
---
spotbugs-exclude.xml | 3 ---
.../com/thealgorithms/searches/LinearSearchThreadTest.java | 6 ++++--
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml
index a8eedcfed402..13d72334e594 100644
--- a/spotbugs-exclude.xml
+++ b/spotbugs-exclude.xml
@@ -11,9 +11,6 @@
-
-
-
diff --git a/src/test/java/com/thealgorithms/searches/LinearSearchThreadTest.java b/src/test/java/com/thealgorithms/searches/LinearSearchThreadTest.java
index 534c2a4487b2..c0d82489209f 100644
--- a/src/test/java/com/thealgorithms/searches/LinearSearchThreadTest.java
+++ b/src/test/java/com/thealgorithms/searches/LinearSearchThreadTest.java
@@ -3,6 +3,7 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.util.Random;
import org.junit.jupiter.api.Test;
class LinearSearchThreadTest {
@@ -62,10 +63,11 @@ void testSearcherEmptySegment() throws InterruptedException {
void testSearcherRandomNumbers() throws InterruptedException {
int size = 200;
int[] array = new int[size];
+ Random random = new Random();
for (int i = 0; i < size; i++) {
- array[i] = (int) (Math.random() * 100);
+ array[i] = random.nextInt(100);
}
- int target = array[(int) (Math.random() * size)]; // Randomly select a target that is present
+ final int target = array[random.nextInt(size)]; // Randomly select a target that is present
Searcher searcher = new Searcher(array, 0, size, target);
searcher.start();
searcher.join();
From 2d443a9991f7a80f1ab6bca437d1b953f7d05420 Mon Sep 17 00:00:00 2001
From: Mohan E <777emohan@gmail.com>
Date: Sat, 21 Feb 2026 18:40:37 +0530
Subject: [PATCH 39/58] Add time and space complexity documentation to
LongestNonRepetitiveSubstring (#7284)
---
.../strings/LongestNonRepetitiveSubstring.java | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/main/java/com/thealgorithms/strings/LongestNonRepetitiveSubstring.java b/src/main/java/com/thealgorithms/strings/LongestNonRepetitiveSubstring.java
index 6808cd50602f..51e8dc6b02c3 100644
--- a/src/main/java/com/thealgorithms/strings/LongestNonRepetitiveSubstring.java
+++ b/src/main/java/com/thealgorithms/strings/LongestNonRepetitiveSubstring.java
@@ -13,6 +13,12 @@ private LongestNonRepetitiveSubstring() {
/**
* Finds the length of the longest substring without repeating characters.
*
+ * Uses the sliding window technique with a HashMap to track
+ * the last seen index of each character.
+ *
+ * Time Complexity: O(n), where n is the length of the input string.
+ * Space Complexity: O(min(n, m)), where m is the size of the character set.
+ *
* @param s the input string
* @return the length of the longest non-repetitive substring
*/
From 109df1f39837d0102646920dcfa353ae3c09e7cc Mon Sep 17 00:00:00 2001
From: Piotr Idzik <65706193+vil02@users.noreply.github.com>
Date: Sat, 21 Feb 2026 16:27:13 +0100
Subject: [PATCH 40/58] style: include `SUA_SUSPICIOUS_UNINITIALIZED_ARRAY`
(#7285)
---
spotbugs-exclude.xml | 3 ---
.../com/thealgorithms/divideandconquer/ClosestPair.java | 4 ----
.../thealgorithms/divideandconquer/ClosestPairTest.java | 8 --------
3 files changed, 15 deletions(-)
diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml
index 13d72334e594..8c42802520e3 100644
--- a/spotbugs-exclude.xml
+++ b/spotbugs-exclude.xml
@@ -96,9 +96,6 @@
-
-
-
diff --git a/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java b/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java
index 4c9c40c83174..323098a99887 100644
--- a/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java
+++ b/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java
@@ -66,10 +66,6 @@ public static class Location {
}
}
- public Location[] createLocation(int numberValues) {
- return new Location[numberValues];
- }
-
public Location buildLocation(double x, double y) {
return new Location(x, y);
}
diff --git a/src/test/java/com/thealgorithms/divideandconquer/ClosestPairTest.java b/src/test/java/com/thealgorithms/divideandconquer/ClosestPairTest.java
index 38784228d68e..b25fd796b112 100644
--- a/src/test/java/com/thealgorithms/divideandconquer/ClosestPairTest.java
+++ b/src/test/java/com/thealgorithms/divideandconquer/ClosestPairTest.java
@@ -16,14 +16,6 @@ public void testBuildLocation() {
assertEquals(4.0, point.y);
}
- @Test
- public void testCreateLocation() {
- ClosestPair cp = new ClosestPair(5);
- ClosestPair.Location[] locations = cp.createLocation(5);
- assertNotNull(locations);
- assertEquals(5, locations.length);
- }
-
@Test
public void testXPartition() {
ClosestPair cp = new ClosestPair(5);
From 12935c291def0a4079c961a0aa7652177b1b05f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=87a=C4=9Flar=20Eker?=
Date: Sun, 22 Feb 2026 21:15:22 +0300
Subject: [PATCH 41/58] Add Longest Repeated Substring algorithm (#7286)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Add Longest Repeated Substring algorithm
Implement LongestRepeatedSubstring in the strings package using the
existing SuffixArray and Kasai's algorithm for LCP array construction.
Includes parameterized unit tests covering typical and edge cases.
* style: reformat test file per clang-format and add coverage test
---------
Co-authored-by: Çağlar Eker
---
.../strings/LongestRepeatedSubstring.java | 83 +++++++++++++++++++
.../strings/LongestRepeatedSubstringTest.java | 33 ++++++++
2 files changed, 116 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/strings/LongestRepeatedSubstring.java
create mode 100644 src/test/java/com/thealgorithms/strings/LongestRepeatedSubstringTest.java
diff --git a/src/main/java/com/thealgorithms/strings/LongestRepeatedSubstring.java b/src/main/java/com/thealgorithms/strings/LongestRepeatedSubstring.java
new file mode 100644
index 000000000000..87c9278fd4bf
--- /dev/null
+++ b/src/main/java/com/thealgorithms/strings/LongestRepeatedSubstring.java
@@ -0,0 +1,83 @@
+package com.thealgorithms.strings;
+
+/**
+ * Finds the longest substring that occurs at least twice in a given string.
+ *
+ * Uses the suffix array (via {@link SuffixArray}) and Kasai's algorithm
+ * to build the LCP (Longest Common Prefix) array, then returns the substring
+ * corresponding to the maximum LCP value.
+ *
+ * Time complexity: O(n log² n) for suffix array construction + O(n) for LCP.
+ *
+ * @see Longest repeated substring problem
+ * @see SuffixArray
+ */
+public final class LongestRepeatedSubstring {
+
+ private LongestRepeatedSubstring() {
+ }
+
+ /**
+ * Returns the longest substring that appears at least twice in the given text.
+ *
+ * @param text the input string
+ * @return the longest repeated substring, or an empty string if none exists
+ */
+ public static String longestRepeatedSubstring(String text) {
+ if (text == null || text.length() <= 1) {
+ return "";
+ }
+
+ final int[] suffixArray = SuffixArray.buildSuffixArray(text);
+ final int[] lcp = buildLcpArray(text, suffixArray);
+
+ int maxLen = 0;
+ int maxIdx = 0;
+ for (int i = 0; i < lcp.length; i++) {
+ if (lcp[i] > maxLen) {
+ maxLen = lcp[i];
+ maxIdx = suffixArray[i + 1];
+ }
+ }
+
+ return text.substring(maxIdx, maxIdx + maxLen);
+ }
+
+ /**
+ * Builds the LCP (Longest Common Prefix) array using Kasai's algorithm.
+ *
+ * LCP[i] is the length of the longest common prefix between the suffixes
+ * at positions suffixArray[i] and suffixArray[i+1] in sorted order.
+ *
+ * @param text the original string
+ * @param suffixArray the suffix array of the string
+ * @return the LCP array of length n-1
+ */
+ static int[] buildLcpArray(String text, int[] suffixArray) {
+ final int n = text.length();
+ final int[] rank = new int[n];
+ final int[] lcp = new int[n - 1];
+
+ for (int i = 0; i < n; i++) {
+ rank[suffixArray[i]] = i;
+ }
+
+ int k = 0;
+ for (int i = 0; i < n; i++) {
+ if (rank[i] == n - 1) {
+ k = 0;
+ continue;
+ }
+ final int j = suffixArray[rank[i] + 1];
+ while (i + k < n && j + k < n && text.charAt(i + k) == text.charAt(j + k)) {
+ k++;
+ }
+ lcp[rank[i]] = k;
+ if (k > 0) {
+ k--;
+ }
+ }
+
+ return lcp;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/strings/LongestRepeatedSubstringTest.java b/src/test/java/com/thealgorithms/strings/LongestRepeatedSubstringTest.java
new file mode 100644
index 000000000000..366f6863340d
--- /dev/null
+++ b/src/test/java/com/thealgorithms/strings/LongestRepeatedSubstringTest.java
@@ -0,0 +1,33 @@
+package com.thealgorithms.strings;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.stream.Stream;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+class LongestRepeatedSubstringTest {
+
+ @ParameterizedTest(name = "\"{0}\" -> \"{1}\"")
+ @MethodSource("provideTestCases")
+ void testLongestRepeatedSubstring(String input, String expected) {
+ assertEquals(expected, LongestRepeatedSubstring.longestRepeatedSubstring(input));
+ }
+
+ private static Stream provideTestCases() {
+ return Stream.of(Arguments.of("banana", "ana"), Arguments.of("abcabc", "abc"), Arguments.of("aaaa", "aaa"), Arguments.of("abcd", ""), Arguments.of("a", ""), Arguments.of("", ""), Arguments.of(null, ""), Arguments.of("aab", "a"), Arguments.of("aa", "a"), Arguments.of("mississippi", "issi"));
+ }
+
+ @ParameterizedTest(name = "\"{0}\" -> LCP={1}")
+ @MethodSource("provideLcpTestCases")
+ void testBuildLcpArray(String input, int[] expectedLcp) {
+ int[] suffixArray = SuffixArray.buildSuffixArray(input);
+ assertArrayEquals(expectedLcp, LongestRepeatedSubstring.buildLcpArray(input, suffixArray));
+ }
+
+ private static Stream provideLcpTestCases() {
+ return Stream.of(Arguments.of("banana", new int[] {1, 3, 0, 0, 2}), Arguments.of("ab", new int[] {0}));
+ }
+}
From 10114b79ae8869e9351c8fd38eca798978119204 Mon Sep 17 00:00:00 2001
From: Vasundhara117
Date: Tue, 24 Feb 2026 00:36:51 +0530
Subject: [PATCH 42/58] Add ReverseQueueRecursion.java: Reverse a Queue using
recursion (#7281)
* Create ReverseQueueRecursion
Add ReverseQueueRecursion.java:
- Reverses a Queue using recursion (generic )
- Includes unit tests in ReverseQueueRecursionTest.java
- Follows repo style (final class, private constructor, Javadoc)
* Create ReverseQueueRecursionTest.java
Add ReverseQueueRecursionTest as required by CONTRIBUTING.md
* Rename ReverseQueueRecursion to ReverseQueueRecursion.java
* Update ReverseQueueRecursion.java
* Update ReverseQueueRecursion.java
* Update ReverseQueueRecursion.java
* Update ReverseQueueRecursion.java
* Update ReverseQueueRecursionTest.java
* Update ReverseQueueRecursion.java
* Update ReverseQueueRecursionTest.java
* Update ReverseQueueRecursionTest.java
* Update ReverseQueueRecursion.java
* Update ReverseQueueRecursionTest.java
* Update ReverseQueueRecursionTest.java
* Update ReverseQueueRecursionTest.java
* Update ReverseQueueRecursionTest.java
* Update ReverseQueueRecursion.java
---
.../queues/ReverseQueueRecursion.java | 28 ++++++++++
.../queues/ReverseQueueRecursionTest.java | 54 +++++++++++++++++++
2 files changed, 82 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/datastructures/queues/ReverseQueueRecursion.java
create mode 100644 src/test/java/com/thealgorithms/datastructures/queues/ReverseQueueRecursionTest.java
diff --git a/src/main/java/com/thealgorithms/datastructures/queues/ReverseQueueRecursion.java b/src/main/java/com/thealgorithms/datastructures/queues/ReverseQueueRecursion.java
new file mode 100644
index 000000000000..79275dcefe20
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/queues/ReverseQueueRecursion.java
@@ -0,0 +1,28 @@
+package com.thealgorithms.datastructures.queues;
+
+import java.util.Queue;
+
+/**
+ * Reverse a queue using recursion.
+ */
+public final class ReverseQueueRecursion {
+ private ReverseQueueRecursion() {
+ // private constructor to prevent instantiation
+ }
+
+ /**
+ * Reverses the given queue recursively.
+ *
+ * @param queue the queue to reverse
+ * @param the type of elements in the queue
+ */
+ public static void reverseQueue(final Queue queue) {
+ if (queue == null || queue.isEmpty()) {
+ return;
+ }
+
+ final T front = queue.poll();
+ reverseQueue(queue);
+ queue.add(front);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/queues/ReverseQueueRecursionTest.java b/src/test/java/com/thealgorithms/datastructures/queues/ReverseQueueRecursionTest.java
new file mode 100644
index 000000000000..e3abe15b6a46
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/queues/ReverseQueueRecursionTest.java
@@ -0,0 +1,54 @@
+package com.thealgorithms.datastructures.queues;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.LinkedList;
+import java.util.Queue;
+import org.junit.jupiter.api.Test;
+
+class ReverseQueueRecursionTest {
+ @Test
+ void testReverseMultipleElements() {
+ Queue queue = new LinkedList<>();
+ queue.add(1);
+ queue.add(2);
+ queue.add(3);
+ queue.add(4);
+ ReverseQueueRecursion.reverseQueue(queue);
+ assertEquals(4, queue.poll());
+ assertEquals(3, queue.poll());
+ assertEquals(2, queue.poll());
+ assertEquals(1, queue.poll());
+ assertTrue(queue.isEmpty());
+ }
+
+ @Test
+ void testReverseSingleElement() {
+ Queue queue = new LinkedList<>();
+ queue.add(42);
+ ReverseQueueRecursion.reverseQueue(queue);
+ assertEquals(42, queue.poll());
+ assertTrue(queue.isEmpty());
+ }
+
+ @Test
+ void testReverseEmptyQueue() {
+ Queue queue = new LinkedList<>();
+ ReverseQueueRecursion.reverseQueue(queue);
+ assertTrue(queue.isEmpty());
+ }
+
+ @Test
+ void testReverseStringQueue() {
+ Queue queue = new LinkedList<>();
+ queue.add("A");
+ queue.add("B");
+ queue.add("C");
+ ReverseQueueRecursion.reverseQueue(queue);
+ assertEquals("C", queue.poll());
+ assertEquals("B", queue.poll());
+ assertEquals("A", queue.poll());
+ assertTrue(queue.isEmpty());
+ }
+}
From 023f856a9bca320e5ab4324e3efb4766ae2f4f54 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 23 Feb 2026 22:55:11 +0100
Subject: [PATCH 43/58] chore(deps-dev): bump
org.apache.maven.plugins:maven-surefire-plugin from 3.5.4 to 3.5.5 (#7288)
chore(deps-dev): bump org.apache.maven.plugins:maven-surefire-plugin
Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.5.4 to 3.5.5.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.4...surefire-3.5.5)
---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
dependency-version: 3.5.5
dependency-type: direct:development
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 2445a1e920a8..96deca50fea8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,7 +61,7 @@
maven-surefire-plugin
- 3.5.4
+ 3.5.5
From 7e5d9d469d8d2deb7309a1003dafdeb884c7dd84 Mon Sep 17 00:00:00 2001
From: Chahat Sandhu
Date: Thu, 26 Feb 2026 05:27:11 -0600
Subject: [PATCH 44/58] feat: add HuffmanCoding with fail-fast validation and
immutable design (#7289)
---
.../compression/HuffmanCoding.java | 253 ++++++++++++++++++
.../compression/HuffmanCodingTest.java | 110 ++++++++
2 files changed, 363 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/compression/HuffmanCoding.java
create mode 100644 src/test/java/com/thealgorithms/compression/HuffmanCodingTest.java
diff --git a/src/main/java/com/thealgorithms/compression/HuffmanCoding.java b/src/main/java/com/thealgorithms/compression/HuffmanCoding.java
new file mode 100644
index 000000000000..d7f9d58d2429
--- /dev/null
+++ b/src/main/java/com/thealgorithms/compression/HuffmanCoding.java
@@ -0,0 +1,253 @@
+package com.thealgorithms.compression;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.PriorityQueue;
+
+/**
+ * Huffman Coding Compression Algorithm Implementation.
+ *
+ * Huffman Coding is a popular greedy algorithm used for lossless data compression.
+ * It reduces the overall size of data by assigning variable-length, prefix-free
+ * binary codes to input characters, ensuring that more frequent characters receive
+ * the shortest possible codes.
+ *
+ *
+ * Key Features:
+ *
+ * - Uses a PriorityQueue (min-heap) to efficiently construct the optimal prefix tree.
+ * - Fail-fast design throws exceptions for unsupported characters and malformed binary payloads.
+ * - Immutable internal dictionary state prevents external tampering with generated codes.
+ * - Robust handling of edge cases, including single-character strings and incomplete sequences.
+ *
+ *
+ * @author Chahat Sandhu, singhc7
+ * @see Huffman Coding (Wikipedia)
+ */
+public class HuffmanCoding {
+
+ private Node root;
+ private final Map huffmanCodes;
+
+ /**
+ * Represents a node within the Huffman Tree.
+ * Implements {@link Comparable} to allow sorting by frequency in a PriorityQueue.
+ */
+ private static class Node implements Comparable {
+ final char ch;
+ final int freq;
+ final Node left;
+ final Node right;
+
+ /**
+ * Constructs a leaf node containing a specific character and its frequency.
+ *
+ * @param ch The character stored in this leaf.
+ * @param freq The frequency of occurrence of the character.
+ */
+ Node(char ch, int freq) {
+ this.ch = ch;
+ this.freq = freq;
+ this.left = null;
+ this.right = null;
+ }
+
+ /**
+ * Constructs an internal node that merges two child nodes.
+ * The character is defaulted to the null character ('\0').
+ *
+ * @param freq The combined frequency of the left and right child nodes.
+ * @param left The left child node.
+ * @param right The right child node.
+ */
+ Node(int freq, Node left, Node right) {
+ this.ch = '\0';
+ this.freq = freq;
+ this.left = left;
+ this.right = right;
+ }
+
+ /**
+ * Determines if the current node is a leaf (contains no children).
+ *
+ * @return {@code true} if both left and right children are null, {@code false} otherwise.
+ */
+ boolean isLeaf() {
+ return left == null && right == null;
+ }
+
+ /**
+ * Compares this node with another node based on their frequencies.
+ * Used by the PriorityQueue to maintain the min-heap property.
+ *
+ * @param other The other Node to compare against.
+ * @return A negative integer, zero, or a positive integer as this node's frequency
+ * is less than, equal to, or greater than the specified node's frequency.
+ */
+ @Override
+ public int compareTo(Node other) {
+ return Integer.compare(this.freq, other.freq);
+ }
+ }
+
+ /**
+ * Initializes the Huffman Tree and generates immutable prefix-free codes
+ * based on the character frequencies in the provided text.
+ *
+ * @param text The input string used to calculate frequencies and build the optimal tree.
+ * If null or empty, an empty tree and dictionary are created.
+ */
+ public HuffmanCoding(String text) {
+ if (text == null || text.isEmpty()) {
+ this.huffmanCodes = Collections.emptyMap();
+ return;
+ }
+
+ Map tempCodes = new HashMap<>();
+ buildTree(text);
+ generateCodes(root, "", tempCodes);
+
+ if (tempCodes.size() == 1) {
+ tempCodes.put(root.ch, "0");
+ }
+
+ this.huffmanCodes = Collections.unmodifiableMap(tempCodes);
+ }
+
+ /**
+ * Computes character frequencies and constructs the Huffman Tree using a min-heap.
+ * The optimal tree is built by repeatedly extracting the two lowest-frequency nodes
+ * and merging them until a single root node remains.
+ *
+ * @param text The input text to analyze.
+ */
+ private void buildTree(String text) {
+ Map freqMap = new HashMap<>();
+ for (char c : text.toCharArray()) {
+ freqMap.put(c, freqMap.getOrDefault(c, 0) + 1);
+ }
+
+ PriorityQueue pq = new PriorityQueue<>();
+ for (Map.Entry entry : freqMap.entrySet()) {
+ pq.add(new Node(entry.getKey(), entry.getValue()));
+ }
+
+ while (pq.size() > 1) {
+ Node left = pq.poll();
+ Node right = pq.poll();
+ pq.add(new Node(left.freq + right.freq, left, right));
+ }
+
+ root = pq.poll();
+ }
+
+ /**
+ * Recursively traverses the Huffman Tree to generate prefix-free binary codes.
+ * Left traversals append a '0' to the code, while right traversals append a '1'.
+ *
+ * @param node The current node in the traversal.
+ * @param code The accumulated binary string for the current path.
+ * @param map The temporary dictionary to populate with the final character-to-code mappings.
+ */
+ private void generateCodes(Node node, String code, Map map) {
+ if (node == null) {
+ return;
+ }
+ if (node.isLeaf()) {
+ map.put(node.ch, code);
+ return;
+ }
+ generateCodes(node.left, code + "0", map);
+ generateCodes(node.right, code + "1", map);
+ }
+
+ /**
+ * Encodes the given plaintext string into a binary string using the generated Huffman dictionary.
+ *
+ * @param text The plaintext string to compress.
+ * @return A string of '0's and '1's representing the compressed data.
+ * Returns an empty string if the input is null or empty.
+ * @throws IllegalStateException If attempting to encode when the Huffman tree is empty.
+ * @throws IllegalArgumentException If the input text contains a character not present
+ * in the original text used to build the tree.
+ */
+ public String encode(String text) {
+ if (text == null || text.isEmpty()) {
+ return "";
+ }
+ if (root == null) {
+ throw new IllegalStateException("Huffman tree is empty.");
+ }
+
+ StringBuilder sb = new StringBuilder();
+ for (char c : text.toCharArray()) {
+ if (!huffmanCodes.containsKey(c)) {
+ throw new IllegalArgumentException(String.format("Character '%c' (U+%04X) not found in Huffman dictionary.", c, (int) c));
+ }
+ sb.append(huffmanCodes.get(c));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Decodes the given binary string back into the original plaintext using the Huffman Tree.
+ * Validates the integrity of the binary payload during traversal.
+ *
+ * @param encodedText The binary string of '0's and '1's to decompress.
+ * @return The reconstructed plaintext string. Returns an empty string if the input is null or empty.
+ * @throws IllegalStateException If attempting to decode when the Huffman tree is empty.
+ * @throws IllegalArgumentException If the binary string contains characters other than '0' or '1',
+ * or if the sequence ends abruptly without reaching a leaf node.
+ */
+ public String decode(String encodedText) {
+ if (encodedText == null || encodedText.isEmpty()) {
+ return "";
+ }
+ if (root == null) {
+ throw new IllegalStateException("Huffman tree is empty.");
+ }
+
+ StringBuilder sb = new StringBuilder();
+
+ if (root.isLeaf()) {
+ for (char bit : encodedText.toCharArray()) {
+ if (bit != '0') {
+ throw new IllegalArgumentException("Invalid binary sequence for single-character tree.");
+ }
+ sb.append(root.ch);
+ }
+ return sb.toString();
+ }
+
+ Node current = root;
+ for (char bit : encodedText.toCharArray()) {
+ if (bit != '0' && bit != '1') {
+ throw new IllegalArgumentException("Encoded text contains invalid characters: " + bit);
+ }
+
+ current = (bit == '0') ? current.left : current.right;
+
+ if (current.isLeaf()) {
+ sb.append(current.ch);
+ current = root;
+ }
+ }
+
+ if (current != root) {
+ throw new IllegalArgumentException("Malformed encoded string: incomplete sequence ending.");
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Retrieves the generated Huffman dictionary mapping characters to their binary codes.
+ *
+ * @return An unmodifiable map containing the character-to-binary-code mappings to prevent
+ * external mutation of the algorithm's state.
+ */
+ public Map getHuffmanCodes() {
+ return huffmanCodes;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/compression/HuffmanCodingTest.java b/src/test/java/com/thealgorithms/compression/HuffmanCodingTest.java
new file mode 100644
index 000000000000..f919417899db
--- /dev/null
+++ b/src/test/java/com/thealgorithms/compression/HuffmanCodingTest.java
@@ -0,0 +1,110 @@
+package com.thealgorithms.compression;
+
+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 org.junit.jupiter.api.Test;
+
+class HuffmanCodingTest {
+
+ @Test
+ void testStandardLifecycle() {
+ String input = "efficiency is key";
+ HuffmanCoding huffman = new HuffmanCoding(input);
+
+ String encoded = huffman.encode(input);
+ assertNotNull(encoded);
+ assertTrue(encoded.matches("[01]+"));
+ assertEquals(input, huffman.decode(encoded));
+ }
+
+ @Test
+ void testNullAndEmptyHandling() {
+ HuffmanCoding huffman = new HuffmanCoding("");
+ assertEquals("", huffman.encode(""));
+ assertEquals("", huffman.decode(""));
+
+ HuffmanCoding huffmanNull = new HuffmanCoding(null);
+ assertEquals("", huffmanNull.encode(null));
+ assertEquals("", huffmanNull.decode(null));
+ }
+
+ @Test
+ void testSingleCharacterEdgeCase() {
+ String input = "aaaaa";
+ HuffmanCoding huffman = new HuffmanCoding(input);
+
+ String encoded = huffman.encode(input);
+ assertEquals("00000", encoded);
+ assertEquals(input, huffman.decode(encoded));
+ }
+
+ @Test
+ void testUnicodeAndSpecialCharacters() {
+ // Tests spacing, symbols, non-latin alphabets, and surrogate pairs (emojis)
+ String input = "Hello, World! 🚀\nLine 2: こんにちは";
+ HuffmanCoding huffman = new HuffmanCoding(input);
+
+ String encoded = huffman.encode(input);
+ assertEquals(input, huffman.decode(encoded));
+ }
+
+ @Test
+ void testFailFastOnUnseenCharacter() {
+ HuffmanCoding huffman = new HuffmanCoding("abc");
+
+ IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
+ () -> huffman.encode("abcd") // 'd' was not in the original tree
+ );
+ assertTrue(exception.getMessage().contains("not found in Huffman dictionary"));
+ }
+
+ @Test
+ void testFailFastOnInvalidBinaryCharacter() {
+ HuffmanCoding huffman = new HuffmanCoding("abc");
+ String encoded = huffman.encode("abc");
+
+ // Inject a '2' into the binary stream
+ String corruptedEncoded = encoded + "2";
+
+ IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> huffman.decode(corruptedEncoded));
+ assertTrue(exception.getMessage().contains("contains invalid characters"));
+ }
+
+ @Test
+ void testFailFastOnIncompleteSequence() {
+ HuffmanCoding huffman = new HuffmanCoding("abcd");
+ String encoded = huffman.encode("abc");
+
+ // Truncate the last bit to simulate an incomplete byte/sequence transfer
+ String truncatedEncoded = encoded.substring(0, encoded.length() - 1);
+
+ IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> huffman.decode(truncatedEncoded));
+ assertTrue(exception.getMessage().contains("incomplete sequence"));
+ }
+
+ @Test
+ void testImmutabilityOfDictionary() {
+ HuffmanCoding huffman = new HuffmanCoding("abc");
+ var codes = huffman.getHuffmanCodes();
+
+ assertThrows(UnsupportedOperationException.class, () -> codes.put('z', "0101"));
+ }
+
+ @Test
+ void testStressVolume() {
+ StringBuilder sb = new StringBuilder();
+ // Generate a 100,000 character string
+ for (int i = 0; i < 100000; i++) {
+ sb.append((char) ('a' + (i % 26)));
+ }
+ String largeInput = sb.toString();
+
+ HuffmanCoding huffman = new HuffmanCoding(largeInput);
+ String encoded = huffman.encode(largeInput);
+
+ assertEquals(largeInput, huffman.decode(encoded));
+ }
+}
From 705eb52833f50e88b1f92d309ac40f770fa56b10 Mon Sep 17 00:00:00 2001
From: kvadrik <41710943+kvadrik@users.noreply.github.com>
Date: Fri, 27 Feb 2026 23:35:42 +0200
Subject: [PATCH 45/58] Added volume of a pyramid frustum (#7291)
* Added volume of a pyramid frustum
Added a function calculating volume of a pyramid frustum, V=(S1+S2+sqrt(S1*S2))*h/3
* compiler error fixed
* Added pyramid frustum test case
* extra space removed
---
src/main/java/com/thealgorithms/maths/Volume.java | 12 ++++++++++++
.../java/com/thealgorithms/maths/VolumeTest.java | 3 +++
2 files changed, 15 insertions(+)
diff --git a/src/main/java/com/thealgorithms/maths/Volume.java b/src/main/java/com/thealgorithms/maths/Volume.java
index 0f282b2abae2..89b0595912b9 100644
--- a/src/main/java/com/thealgorithms/maths/Volume.java
+++ b/src/main/java/com/thealgorithms/maths/Volume.java
@@ -102,4 +102,16 @@ public static double volumePyramid(double baseArea, double height) {
public static double volumeFrustumOfCone(double r1, double r2, double height) {
return (Math.PI * height / 3) * (r1 * r1 + r2 * r2 + r1 * r2);
}
+
+ /**
+ * Calculate the volume of a frustum of a pyramid.
+ *
+ * @param upperBaseArea area of the upper base
+ * @param lowerBaseArea area of the lower base
+ * @param height height of the frustum
+ * @return volume of the frustum
+ */
+ public static double volumeFrustumOfPyramid(double upperBaseArea, double lowerBaseArea, double height) {
+ return (upperBaseArea + lowerBaseArea + Math.sqrt(upperBaseArea * lowerBaseArea)) * height / 3;
+ }
}
diff --git a/src/test/java/com/thealgorithms/maths/VolumeTest.java b/src/test/java/com/thealgorithms/maths/VolumeTest.java
index af882eef7563..cf72d7084e75 100644
--- a/src/test/java/com/thealgorithms/maths/VolumeTest.java
+++ b/src/test/java/com/thealgorithms/maths/VolumeTest.java
@@ -35,5 +35,8 @@ public void volume() {
/* test frustum */
assertEquals(359.188760060433, Volume.volumeFrustumOfCone(3, 5, 7));
+
+ /* test pyramid frustum */
+ assertEquals(140.0, Volume.volumeFrustumOfPyramid(6, 24, 10));
}
}
From ba286b24d66972150547fc6683eaa1925743e9d5 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 27 Feb 2026 22:52:50 +0100
Subject: [PATCH 46/58] chore(deps-dev): bump org.mockito:mockito-core from
5.21.0 to 5.22.0 (#7292)
Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.21.0 to 5.22.0.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v5.21.0...v5.22.0)
---
updated-dependencies:
- dependency-name: org.mockito:mockito-core
dependency-version: 5.22.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>
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 96deca50fea8..7c614f31e52e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -42,7 +42,7 @@
org.mockito
mockito-core
- 5.21.0
+ 5.22.0
test
From 0d2a98e9f87dc7bd5dde732a8d34a6bcaef43400 Mon Sep 17 00:00:00 2001
From: kvadrik <41710943+kvadrik@users.noreply.github.com>
Date: Sat, 28 Feb 2026 21:08:50 +0200
Subject: [PATCH 47/58] Added volume of a torus (#7294)
* Added volume of a torus
Added function calculation the volume of a torus according to the formula:
V = 2 * pi^2 * R * r^2
where R is the major radius and r is the minor radius of the torus.
* Added test for torus volume
---
src/main/java/com/thealgorithms/maths/Volume.java | 11 +++++++++++
src/test/java/com/thealgorithms/maths/VolumeTest.java | 3 +++
2 files changed, 14 insertions(+)
diff --git a/src/main/java/com/thealgorithms/maths/Volume.java b/src/main/java/com/thealgorithms/maths/Volume.java
index 89b0595912b9..c0898c5424a0 100644
--- a/src/main/java/com/thealgorithms/maths/Volume.java
+++ b/src/main/java/com/thealgorithms/maths/Volume.java
@@ -114,4 +114,15 @@ public static double volumeFrustumOfCone(double r1, double r2, double height) {
public static double volumeFrustumOfPyramid(double upperBaseArea, double lowerBaseArea, double height) {
return (upperBaseArea + lowerBaseArea + Math.sqrt(upperBaseArea * lowerBaseArea)) * height / 3;
}
+
+ /**
+ * Calculate the volume of a torus.
+ *
+ * @param majorRadius major radius of a torus
+ * @param minorRadius minor radius of a torus
+ * @return volume of the torus
+ */
+ public static double volumeTorus(double majorRadius, double minorRadius) {
+ return 2 * Math.PI * Math.PI * majorRadius * minorRadius * minorRadius;
+ }
}
diff --git a/src/test/java/com/thealgorithms/maths/VolumeTest.java b/src/test/java/com/thealgorithms/maths/VolumeTest.java
index cf72d7084e75..c159d7566b46 100644
--- a/src/test/java/com/thealgorithms/maths/VolumeTest.java
+++ b/src/test/java/com/thealgorithms/maths/VolumeTest.java
@@ -38,5 +38,8 @@ public void volume() {
/* test pyramid frustum */
assertEquals(140.0, Volume.volumeFrustumOfPyramid(6, 24, 10));
+
+ /* test torus */
+ assertEquals(39.47841760435743, Volume.volumeTorus(2, 1));
}
}
From d8672882bfebc8cf85f184da461880c84aa7cb92 Mon Sep 17 00:00:00 2001
From: kvadrik <41710943+kvadrik@users.noreply.github.com>
Date: Sat, 28 Feb 2026 21:13:19 +0200
Subject: [PATCH 48/58] Added surface area of a cuboid (#7293)
* Added surface area of a cuboid
Added surface area of a cuboid according to the formula:
S = 2 * (ab + ac + bc)
* Removed extra white space
* Added test for cuboid surface area
* fixed syntax error
* Removed extra space
* Added tests for cuboid surface area that should fail
I have added tests for cuboid surface area where one of the parameters is invalid. These should fail.
---
.../java/com/thealgorithms/maths/Area.java | 21 +++++++++++++++++++
.../com/thealgorithms/maths/AreaTest.java | 11 ++++++++++
2 files changed, 32 insertions(+)
diff --git a/src/main/java/com/thealgorithms/maths/Area.java b/src/main/java/com/thealgorithms/maths/Area.java
index 08807580cb03..84fc67159379 100644
--- a/src/main/java/com/thealgorithms/maths/Area.java
+++ b/src/main/java/com/thealgorithms/maths/Area.java
@@ -35,6 +35,27 @@ public static double surfaceAreaCube(final double sideLength) {
return 6 * sideLength * sideLength;
}
+ /**
+ * Calculate the surface area of a cuboid.
+ *
+ * @param length length of the cuboid
+ * @param width width of the cuboid
+ * @param height height of the cuboid
+ * @return surface area of given cuboid
+ */
+ public static double surfaceAreaCuboid(final double length, double width, double height) {
+ if (length <= 0) {
+ throw new IllegalArgumentException("Length must be greater than 0");
+ }
+ if (width <= 0) {
+ throw new IllegalArgumentException("Width must be greater than 0");
+ }
+ if (height <= 0) {
+ throw new IllegalArgumentException("Height must be greater than 0");
+ }
+ return 2 * (length * width + length * height + width * height);
+ }
+
/**
* Calculate the surface area of a sphere.
*
diff --git a/src/test/java/com/thealgorithms/maths/AreaTest.java b/src/test/java/com/thealgorithms/maths/AreaTest.java
index b28afb85fbc3..1c2fe53ff3f3 100644
--- a/src/test/java/com/thealgorithms/maths/AreaTest.java
+++ b/src/test/java/com/thealgorithms/maths/AreaTest.java
@@ -16,6 +16,11 @@ void testSurfaceAreaCube() {
assertEquals(6.0, Area.surfaceAreaCube(1));
}
+ @Test
+ void testSurfaceAreaCuboid() {
+ assertEquals(214.0, Area.surfaceAreaCuboid(5, 6, 7));
+ }
+
@Test
void testSurfaceAreaSphere() {
assertEquals(12.566370614359172, Area.surfaceAreaSphere(1));
@@ -70,6 +75,12 @@ void surfaceAreaCone() {
void testAllIllegalInput() {
assertAll(()
-> assertThrows(IllegalArgumentException.class, () -> Area.surfaceAreaCube(0)),
+ ()
+ -> assertThrows(IllegalArgumentException.class, () -> Area.surfaceAreaCuboid(0, 1, 2)),
+ ()
+ -> assertThrows(IllegalArgumentException.class, () -> Area.surfaceAreaCuboid(1, 0, 2)),
+ ()
+ -> assertThrows(IllegalArgumentException.class, () -> Area.surfaceAreaCuboid(1, 2, 0)),
()
-> assertThrows(IllegalArgumentException.class, () -> Area.surfaceAreaSphere(0)),
()
From 4b04ad4a836ad87d6d4adf3bf395c0aade96bb07 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 2 Mar 2026 19:56:39 +0100
Subject: [PATCH 49/58] chore(deps): bump com.puppycrawl.tools:checkstyle from
13.2.0 to 13.3.0 (#7295)
Bumps [com.puppycrawl.tools:checkstyle](https://github.com/checkstyle/checkstyle) from 13.2.0 to 13.3.0.
- [Release notes](https://github.com/checkstyle/checkstyle/releases)
- [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-13.2.0...checkstyle-13.3.0)
---
updated-dependencies:
- dependency-name: com.puppycrawl.tools:checkstyle
dependency-version: 13.3.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>
Co-authored-by: a <19151554+alxkm@users.noreply.github.com>
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 7c614f31e52e..b2192fb9a64a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -112,7 +112,7 @@
com.puppycrawl.tools
checkstyle
- 13.2.0
+ 13.3.0
From 9875648a835ac49b9502c0b6c4816780b4f0462b Mon Sep 17 00:00:00 2001
From: Alex Tumanov
Date: Thu, 5 Mar 2026 07:34:33 -0600
Subject: [PATCH 50/58] feat: add TopKFrequentWords with deterministic
tie-breaking (#7298) (#7297)
* feat: add TopKFrequentWords with deterministic tie-breaking
* style: format TopKFrequentWords files with clang-format
---
.../strings/TopKFrequentWords.java | 56 +++++++++++++++++++
.../strings/TopKFrequentWordsTest.java | 34 +++++++++++
2 files changed, 90 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/strings/TopKFrequentWords.java
create mode 100644 src/test/java/com/thealgorithms/strings/TopKFrequentWordsTest.java
diff --git a/src/main/java/com/thealgorithms/strings/TopKFrequentWords.java b/src/main/java/com/thealgorithms/strings/TopKFrequentWords.java
new file mode 100644
index 000000000000..106de304cf40
--- /dev/null
+++ b/src/main/java/com/thealgorithms/strings/TopKFrequentWords.java
@@ -0,0 +1,56 @@
+package com.thealgorithms.strings;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Utility class to find the top-k most frequent words.
+ *
+ * Words are ranked by frequency in descending order. For equal frequencies,
+ * words are ranked in lexicographical ascending order.
+ *
+ *
Reference:
+ * https://en.wikipedia.org/wiki/Top-k_problem
+ *
+ */
+public final class TopKFrequentWords {
+ private TopKFrequentWords() {
+ }
+
+ /**
+ * Finds the k most frequent words.
+ *
+ * @param words input array of words
+ * @param k number of words to return
+ * @return list of top-k words ordered by frequency then lexicographical order
+ * @throws IllegalArgumentException if words is null, k is negative, or words contains null
+ */
+ public static List findTopKFrequentWords(String[] words, int k) {
+ if (words == null) {
+ throw new IllegalArgumentException("Input words array cannot be null.");
+ }
+ if (k < 0) {
+ throw new IllegalArgumentException("k cannot be negative.");
+ }
+ if (k == 0 || words.length == 0) {
+ return List.of();
+ }
+
+ Map frequency = new HashMap<>();
+ for (String word : words) {
+ if (word == null) {
+ throw new IllegalArgumentException("Input words cannot contain null values.");
+ }
+ frequency.put(word, frequency.getOrDefault(word, 0) + 1);
+ }
+
+ List candidates = new ArrayList<>(frequency.keySet());
+ candidates.sort(Comparator.comparingInt(frequency::get).reversed().thenComparing(Comparator.naturalOrder()));
+
+ int limit = Math.min(k, candidates.size());
+ return new ArrayList<>(candidates.subList(0, limit));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/strings/TopKFrequentWordsTest.java b/src/test/java/com/thealgorithms/strings/TopKFrequentWordsTest.java
new file mode 100644
index 000000000000..42b2d04ff265
--- /dev/null
+++ b/src/test/java/com/thealgorithms/strings/TopKFrequentWordsTest.java
@@ -0,0 +1,34 @@
+package com.thealgorithms.strings;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.List;
+import java.util.stream.Stream;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+class TopKFrequentWordsTest {
+
+ @ParameterizedTest
+ @MethodSource("validTestCases")
+ void testFindTopKFrequentWords(String[] words, int k, List expected) {
+ assertEquals(expected, TopKFrequentWords.findTopKFrequentWords(words, k));
+ }
+
+ static Stream validTestCases() {
+ return Stream.of(Arguments.of(new String[] {"i", "love", "leetcode", "i", "love", "coding"}, 2, List.of("i", "love")), Arguments.of(new String[] {"the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"}, 4, List.of("the", "is", "sunny", "day")),
+ Arguments.of(new String[] {"bbb", "aaa", "bbb", "aaa", "ccc"}, 2, List.of("aaa", "bbb")), Arguments.of(new String[] {"one", "two", "three"}, 10, List.of("one", "three", "two")), Arguments.of(new String[] {}, 3, List.of()), Arguments.of(new String[] {"x", "x", "y"}, 0, List.of()));
+ }
+
+ @ParameterizedTest
+ @MethodSource("invalidTestCases")
+ void testFindTopKFrequentWordsInvalidInput(String[] words, int k) {
+ assertThrows(IllegalArgumentException.class, () -> TopKFrequentWords.findTopKFrequentWords(words, k));
+ }
+
+ static Stream invalidTestCases() {
+ return Stream.of(Arguments.of((String[]) null, 1), Arguments.of(new String[] {"a", null, "b"}, 2), Arguments.of(new String[] {"a"}, -1));
+ }
+}
From 8b41533d004babdd641ad70f80e50cf6c1746ebe Mon Sep 17 00:00:00 2001
From: Kakkirala Reshma <24wh1a05q3@bvrithyderabad.edu.in>
Date: Fri, 6 Mar 2026 19:41:57 +0530
Subject: [PATCH 51/58] Add Javadoc comments for AnyBaseToAnyBase class (#7301)
Added Javadoc comments to describe the algorithm and its complexities.
---
.../com/thealgorithms/conversions/AnyBaseToAnyBase.java | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java b/src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java
index 7a9448fd8fe7..7698cc832981 100644
--- a/src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java
+++ b/src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java
@@ -1,3 +1,10 @@
+/**
+ * [Brief description of what the algorithm does]
+ *
+ * Time Complexity: O(n) [or appropriate complexity]
+ * Space Complexity: O(n)
+ * * @author Reshma Kakkirala
+ */
package com.thealgorithms.conversions;
import java.util.Arrays;
From 9aa2544f61566c5e715d56e1a76e51692c26eb37 Mon Sep 17 00:00:00 2001
From: Debojeet Bhattacharya
Date: Sun, 8 Mar 2026 09:27:33 -0500
Subject: [PATCH 52/58] Renamed method variables (#7296)
* renamed method variables for improved readibility in the sort method of InsertionSort
* Renamed method in PancackeSort.
* Renamed array "aux" to "tempArray"
---------
Co-authored-by: Deniz Altunkapan
---
.../thealgorithms/sorts/InsertionSort.java | 30 +++++++++----------
.../com/thealgorithms/sorts/MergeSort.java | 16 +++++-----
.../com/thealgorithms/sorts/PancakeSort.java | 4 +--
3 files changed, 25 insertions(+), 25 deletions(-)
diff --git a/src/main/java/com/thealgorithms/sorts/InsertionSort.java b/src/main/java/com/thealgorithms/sorts/InsertionSort.java
index fdbfd9cd1cfa..1e42f2a61271 100644
--- a/src/main/java/com/thealgorithms/sorts/InsertionSort.java
+++ b/src/main/java/com/thealgorithms/sorts/InsertionSort.java
@@ -33,30 +33,30 @@ public > T[] sort(T[] array) {
}
/**
- * Sorts a subarray of the given array using the standard Insertion Sort algorithm.
+ * Sorts a subarray of the given items using the standard Insertion Sort algorithm.
*
- * @param array The array to be sorted
- * @param lo The starting index of the subarray
- * @param hi The ending index of the subarray (exclusive)
- * @param The type of elements in the array, which must be comparable
- * @return The sorted array
+ * @param items The items to be sorted
+ * @param startIndex The starting index of the subarray
+ * @param endIndex The ending index of the subarray (exclusive)
+ * @param The type of elements in the items, which must be comparable
+ * @return The sorted items
*/
- public > T[] sort(T[] array, final int lo, final int hi) {
- if (array == null || lo >= hi) {
- return array;
+ public > T[] sort(T[] items, final int startIndex, final int endIndex) {
+ if (items == null || startIndex >= endIndex) {
+ return items;
}
- for (int i = lo + 1; i < hi; i++) {
- final T key = array[i];
+ for (int i = startIndex + 1; i < endIndex; i++) {
+ final T key = items[i];
int j = i - 1;
- while (j >= lo && SortUtils.less(key, array[j])) {
- array[j + 1] = array[j];
+ while (j >= startIndex && SortUtils.less(key, items[j])) {
+ items[j + 1] = items[j];
j--;
}
- array[j + 1] = key;
+ items[j + 1] = key;
}
- return array;
+ return items;
}
/**
diff --git a/src/main/java/com/thealgorithms/sorts/MergeSort.java b/src/main/java/com/thealgorithms/sorts/MergeSort.java
index f7a7c8da004d..5db9c48b4f61 100644
--- a/src/main/java/com/thealgorithms/sorts/MergeSort.java
+++ b/src/main/java/com/thealgorithms/sorts/MergeSort.java
@@ -10,7 +10,7 @@
@SuppressWarnings("rawtypes")
class MergeSort implements SortAlgorithm {
- private Comparable[] aux;
+ private Comparable[] tempArray;
/**
* Generic merge sort algorithm.
@@ -26,7 +26,7 @@ class MergeSort implements SortAlgorithm {
*/
@Override
public > T[] sort(T[] unsorted) {
- aux = new Comparable[unsorted.length];
+ tempArray = new Comparable[unsorted.length];
doSort(unsorted, 0, unsorted.length - 1);
return unsorted;
}
@@ -58,17 +58,17 @@ private > void doSort(T[] arr, int left, int right) {
private > void merge(T[] arr, int left, int mid, int right) {
int i = left;
int j = mid + 1;
- System.arraycopy(arr, left, aux, left, right + 1 - left);
+ System.arraycopy(arr, left, tempArray, left, right + 1 - left);
for (int k = left; k <= right; k++) {
if (j > right) {
- arr[k] = (T) aux[i++];
+ arr[k] = (T) tempArray[i++];
} else if (i > mid) {
- arr[k] = (T) aux[j++];
- } else if (less(aux[j], aux[i])) {
- arr[k] = (T) aux[j++];
+ arr[k] = (T) tempArray[j++];
+ } else if (less(tempArray[j], tempArray[i])) {
+ arr[k] = (T) tempArray[j++];
} else {
- arr[k] = (T) aux[i++];
+ arr[k] = (T) tempArray[i++];
}
}
}
diff --git a/src/main/java/com/thealgorithms/sorts/PancakeSort.java b/src/main/java/com/thealgorithms/sorts/PancakeSort.java
index 6079672a1d77..6522aefd7ae3 100644
--- a/src/main/java/com/thealgorithms/sorts/PancakeSort.java
+++ b/src/main/java/com/thealgorithms/sorts/PancakeSort.java
@@ -15,7 +15,7 @@ public > T[] sort(T[] array) {
}
for (int currentSize = 0; currentSize < array.length; currentSize++) {
- int maxIndex = findMaxIndex(array, currentSize);
+ int maxIndex = findIndexOfMax(array, currentSize);
SortUtils.flip(array, maxIndex, array.length - 1 - currentSize);
}
@@ -30,7 +30,7 @@ public > T[] sort(T[] array) {
* @param the type of elements in the array
* @return the index of the maximum element
*/
- private > int findMaxIndex(T[] array, int currentSize) {
+ private > int findIndexOfMax(T[] array, int currentSize) {
T max = array[0];
int maxIndex = 0;
for (int i = 0; i < array.length - currentSize; i++) {
From 8e1f12447c23b0ac9179e76e4adef6b75ecc10e7 Mon Sep 17 00:00:00 2001
From: lmj798 <2757400745@qq.com>
Date: Wed, 11 Mar 2026 21:31:15 +0800
Subject: [PATCH 53/58] test: enhance GenericHashMapUsingArrayTest with
comprehensive edge case coverage (#7300)
* test: enhance GenericHashMapUsingArrayTest with additional edge case coverage
* Removed unused assertion 'assertNotEquals' from imports.
* Simplify import statements in GenericHashMapUsingArrayTest
* Refactor assertions to use Assertions class
* Refactor null key test to use variable
---
.../hashing/GenericHashMapUsingArrayTest.java | 190 +++++++++++++++---
1 file changed, 164 insertions(+), 26 deletions(-)
diff --git a/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayTest.java b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayTest.java
index 5d1733a3e97c..6b6e670a258b 100644
--- a/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayTest.java
@@ -1,11 +1,9 @@
package com.thealgorithms.datastructures.hashmap.hashing;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
class GenericHashMapUsingArrayTest {
@@ -16,10 +14,10 @@ void testGenericHashmapWhichUsesArrayAndBothKeyAndValueAreStrings() {
map.put("Nepal", "Kathmandu");
map.put("India", "New Delhi");
map.put("Australia", "Sydney");
- assertNotNull(map);
- assertEquals(4, map.size());
- assertEquals("Kathmandu", map.get("Nepal"));
- assertEquals("Sydney", map.get("Australia"));
+ Assertions.assertNotNull(map);
+ Assertions.assertEquals(4, map.size());
+ Assertions.assertEquals("Kathmandu", map.get("Nepal"));
+ Assertions.assertEquals("Sydney", map.get("Australia"));
}
@Test
@@ -29,12 +27,12 @@ void testGenericHashmapWhichUsesArrayAndKeyIsStringValueIsInteger() {
map.put("Nepal", 25);
map.put("India", 101);
map.put("Australia", 99);
- assertNotNull(map);
- assertEquals(4, map.size());
- assertEquals(25, map.get("Nepal"));
- assertEquals(99, map.get("Australia"));
+ Assertions.assertNotNull(map);
+ Assertions.assertEquals(4, map.size());
+ Assertions.assertEquals(25, map.get("Nepal"));
+ Assertions.assertEquals(99, map.get("Australia"));
map.remove("Nepal");
- assertFalse(map.containsKey("Nepal"));
+ Assertions.assertFalse(map.containsKey("Nepal"));
}
@Test
@@ -44,11 +42,11 @@ void testGenericHashmapWhichUsesArrayAndKeyIsIntegerValueIsString() {
map.put(34, "Kathmandu");
map.put(46, "New Delhi");
map.put(89, "Sydney");
- assertNotNull(map);
- assertEquals(4, map.size());
- assertEquals("Sydney", map.get(89));
- assertEquals("Washington DC", map.get(101));
- assertTrue(map.containsKey(46));
+ Assertions.assertNotNull(map);
+ Assertions.assertEquals(4, map.size());
+ Assertions.assertEquals("Sydney", map.get(89));
+ Assertions.assertEquals("Washington DC", map.get(101));
+ Assertions.assertTrue(map.containsKey(46));
}
@Test
@@ -56,7 +54,7 @@ void testRemoveNonExistentKey() {
GenericHashMapUsingArray map = new GenericHashMapUsingArray<>();
map.put("USA", "Washington DC");
map.remove("Nepal"); // Attempting to remove a non-existent key
- assertEquals(1, map.size()); // Size should remain the same
+ Assertions.assertEquals(1, map.size()); // Size should remain the same
}
@Test
@@ -65,8 +63,8 @@ void testRehashing() {
for (int i = 0; i < 20; i++) {
map.put("Key" + i, "Value" + i);
}
- assertEquals(20, map.size()); // Ensure all items were added
- assertEquals("Value5", map.get("Key5")); // Check retrieval after rehash
+ Assertions.assertEquals(20, map.size()); // Ensure all items were added
+ Assertions.assertEquals("Value5", map.get("Key5")); // Check retrieval after rehash
}
@Test
@@ -74,7 +72,7 @@ void testUpdateValueForExistingKey() {
GenericHashMapUsingArray map = new GenericHashMapUsingArray<>();
map.put("USA", "Washington DC");
map.put("USA", "New Washington DC"); // Updating value for existing key
- assertEquals("New Washington DC", map.get("USA"));
+ Assertions.assertEquals("New Washington DC", map.get("USA"));
}
@Test
@@ -83,14 +81,154 @@ void testToStringMethod() {
map.put("USA", "Washington DC");
map.put("Nepal", "Kathmandu");
String expected = "{USA : Washington DC, Nepal : Kathmandu}";
- assertEquals(expected, map.toString());
+ Assertions.assertEquals(expected, map.toString());
}
@Test
void testContainsKey() {
GenericHashMapUsingArray map = new GenericHashMapUsingArray<>();
map.put("USA", "Washington DC");
- assertTrue(map.containsKey("USA"));
- assertFalse(map.containsKey("Nepal"));
+ Assertions.assertTrue(map.containsKey("USA"));
+ Assertions.assertFalse(map.containsKey("Nepal"));
+ }
+
+ // ======= Added tests from the new version =======
+
+ @Test
+ void shouldThrowNullPointerExceptionForNullKey() {
+ GenericHashMapUsingArray map = new GenericHashMapUsingArray<>();
+ String nullKey = null; // Use variable to avoid static analysis false positive
+ Assertions.assertThrows(NullPointerException.class, () -> map.put(nullKey, "value"));
+ }
+
+ @Test
+ void shouldStoreNullValueForKey() {
+ GenericHashMapUsingArray map = new GenericHashMapUsingArray<>();
+ map.put("keyWithNullValue", null);
+ Assertions.assertEquals(1, map.size());
+ Assertions.assertNull(map.get("keyWithNullValue"));
+ // Note: containsKey returns false for null values due to implementation
+ Assertions.assertFalse(map.containsKey("keyWithNullValue"));
+ }
+
+ @Test
+ void shouldHandleCollisionWhenKeysHashToSameBucket() {
+ GenericHashMapUsingArray map = new GenericHashMapUsingArray<>();
+ Integer key1 = 1;
+ Integer key2 = 17;
+ map.put(key1, 100);
+ map.put(key2, 200);
+ Assertions.assertEquals(2, map.size());
+ Assertions.assertEquals(100, map.get(key1));
+ Assertions.assertEquals(200, map.get(key2));
+ Assertions.assertTrue(map.containsKey(key1));
+ Assertions.assertTrue(map.containsKey(key2));
+ }
+
+ @Test
+ void shouldHandleEmptyStringAsKey() {
+ GenericHashMapUsingArray map = new GenericHashMapUsingArray<>();
+ map.put("", "valueForEmptyKey");
+ Assertions.assertEquals(1, map.size());
+ Assertions.assertEquals("valueForEmptyKey", map.get(""));
+ Assertions.assertTrue(map.containsKey(""));
+ }
+
+ @Test
+ void shouldHandleEmptyStringAsValue() {
+ GenericHashMapUsingArray map = new GenericHashMapUsingArray<>();
+ map.put("keyForEmptyValue", "");
+ Assertions.assertEquals(1, map.size());
+ Assertions.assertEquals("", map.get("keyForEmptyValue"));
+ Assertions.assertTrue(map.containsKey("keyForEmptyValue"));
+ }
+
+ @Test
+ void shouldHandleNegativeIntegerKeys() {
+ GenericHashMapUsingArray map = new GenericHashMapUsingArray<>();
+ map.put(-1, 100);
+ map.put(-100, 200);
+ Assertions.assertEquals(2, map.size());
+ Assertions.assertEquals(100, map.get(-1));
+ Assertions.assertEquals(200, map.get(-100));
+ Assertions.assertTrue(map.containsKey(-1));
+ Assertions.assertTrue(map.containsKey(-100));
+ }
+
+ @Test
+ void shouldHandleZeroAsKey() {
+ GenericHashMapUsingArray map = new GenericHashMapUsingArray<>();
+ map.put(0, 100);
+ Assertions.assertEquals(1, map.size());
+ Assertions.assertEquals(100, map.get(0));
+ Assertions.assertTrue(map.containsKey(0));
+ }
+
+ @Test
+ void shouldHandleStringWithSpecialCharacters() {
+ GenericHashMapUsingArray map = new GenericHashMapUsingArray<>();
+ map.put("key!@#$%^&*()", "value<>?/\\|");
+ Assertions.assertEquals(1, map.size());
+ Assertions.assertEquals("value<>?/\\|", map.get("key!@#$%^&*()"));
+ Assertions.assertTrue(map.containsKey("key!@#$%^&*()"));
+ }
+
+ @Test
+ void shouldHandleLongStrings() {
+ GenericHashMapUsingArray map = new GenericHashMapUsingArray<>();
+ StringBuilder longKey = new StringBuilder();
+ StringBuilder longValue = new StringBuilder();
+ for (int i = 0; i < 1000; i++) {
+ longKey.append("a");
+ longValue.append("b");
+ }
+ String key = longKey.toString();
+ String value = longValue.toString();
+ map.put(key, value);
+ Assertions.assertEquals(1, map.size());
+ Assertions.assertEquals(value, map.get(key));
+ Assertions.assertTrue(map.containsKey(key));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"a", "ab", "abc", "test", "longerString"})
+ void shouldHandleKeysOfDifferentLengths(String key) {
+ GenericHashMapUsingArray map = new GenericHashMapUsingArray<>();
+ map.put(key, "value");
+ Assertions.assertEquals(1, map.size());
+ Assertions.assertEquals("value", map.get(key));
+ Assertions.assertTrue(map.containsKey(key));
+ }
+
+ @Test
+ void shouldHandleUpdateOnExistingKeyInCollisionBucket() {
+ GenericHashMapUsingArray map = new GenericHashMapUsingArray<>();
+ Integer key1 = 1;
+ Integer key2 = 17;
+ map.put(key1, 100);
+ map.put(key2, 200);
+ Assertions.assertEquals(2, map.size());
+ map.put(key2, 999);
+ Assertions.assertEquals(2, map.size());
+ Assertions.assertEquals(100, map.get(key1));
+ Assertions.assertEquals(999, map.get(key2));
+ Assertions.assertTrue(map.containsKey(key1));
+ Assertions.assertTrue(map.containsKey(key2));
+ }
+
+ @Test
+ void shouldHandleExactlyLoadFactorBoundary() {
+ GenericHashMapUsingArray map = new GenericHashMapUsingArray<>();
+ // Fill exactly to load factor (12 items with capacity 16 and 0.75 load factor)
+ for (int i = 0; i < 12; i++) {
+ map.put(i, i * 10);
+ }
+ Assertions.assertEquals(12, map.size());
+ // Act - This should trigger rehash on 13th item
+ map.put(12, 120);
+ // Assert - Rehash should have happened
+ Assertions.assertEquals(13, map.size());
+ Assertions.assertEquals(120, map.get(12));
+ Assertions.assertTrue(map.containsKey(12));
}
}
From 5e06b1592638ac0826258341398f92537717eac3 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 11 Mar 2026 23:12:37 +0100
Subject: [PATCH 54/58] chore(deps-dev): bump org.mockito:mockito-core from
5.22.0 to 5.23.0 (#7305)
Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.22.0 to 5.23.0.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v5.22.0...v5.23.0)
---
updated-dependencies:
- dependency-name: org.mockito:mockito-core
dependency-version: 5.23.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>
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index b2192fb9a64a..dab7447430e5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -42,7 +42,7 @@
org.mockito
mockito-core
- 5.22.0
+ 5.23.0
test
From 8bbd090e0cc7cf0dc9b2e3e74f9a33ca8dc297e6 Mon Sep 17 00:00:00 2001
From: kvadrik <41710943+kvadrik@users.noreply.github.com>
Date: Sat, 14 Mar 2026 23:09:19 +0200
Subject: [PATCH 55/58] Overlapping condition changed (#7314)
Overlapping happens not when centers of circular bodies are in the same point, but when the distance between them is smaller than the sum of their radii.
---
src/main/java/com/thealgorithms/physics/ElasticCollision2D.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/physics/ElasticCollision2D.java b/src/main/java/com/thealgorithms/physics/ElasticCollision2D.java
index 399c3f1e041f..d096e0a8d7cd 100644
--- a/src/main/java/com/thealgorithms/physics/ElasticCollision2D.java
+++ b/src/main/java/com/thealgorithms/physics/ElasticCollision2D.java
@@ -41,7 +41,7 @@ public static void resolveCollision(Body a, Body b) {
double dy = b.y - a.y;
double dist = Math.hypot(dx, dy);
- if (dist == 0) {
+ if (dist < a.radius + b.radius) {
return; // overlapping
}
From 24c2beae463b7b1f8c2616110911449589af482b Mon Sep 17 00:00:00 2001
From: Maryam Hazrati <117775713+Maryamh12@users.noreply.github.com>
Date: Sat, 14 Mar 2026 21:15:50 +0000
Subject: [PATCH 56/58] Improve space complexity to O(1) in WordSearch. (#7308)
* Modifying space complexity to O(1).
* Fix formatting using clang-format.
* Fix checkstyle violations.
* Fix checkstyle violations and code formatting.
* Remove unused fields reported by SpotBugs.
* Remove unused fields and comments.
* Remove unused field reported by SpotBugs.
* Fix PMD collapsible if statement.
* Fix indentation to satisfy clang-format.
---------
Co-authored-by: Deniz Altunkapan
---
.../backtracking/WordSearch.java | 66 +++++++------------
1 file changed, 25 insertions(+), 41 deletions(-)
diff --git a/src/main/java/com/thealgorithms/backtracking/WordSearch.java b/src/main/java/com/thealgorithms/backtracking/WordSearch.java
index 174ca90ccaab..452f17b6ace6 100644
--- a/src/main/java/com/thealgorithms/backtracking/WordSearch.java
+++ b/src/main/java/com/thealgorithms/backtracking/WordSearch.java
@@ -35,22 +35,6 @@
* - Stack space for the recursive DFS function, where L is the maximum depth of recursion (length of the word).
*/
public class WordSearch {
- private final int[] dx = {0, 0, 1, -1};
- private final int[] dy = {1, -1, 0, 0};
- private boolean[][] visited;
- private char[][] board;
- private String word;
-
- /**
- * Checks if the given (x, y) coordinates are valid positions in the board.
- *
- * @param x The row index.
- * @param y The column index.
- * @return True if the coordinates are within the bounds of the board; false otherwise.
- */
- private boolean isValid(int x, int y) {
- return x >= 0 && x < board.length && y >= 0 && y < board[0].length;
- }
/**
* Performs Depth First Search (DFS) from the cell (x, y)
@@ -58,28 +42,27 @@ private boolean isValid(int x, int y) {
*
* @param x The current row index.
* @param y The current column index.
- * @param nextIdx The index of the next character in the word to be matched.
+ * @param idx The index of the next character in the word to be matched.
* @return True if a valid path is found to match the remaining characters of the word; false otherwise.
*/
- private boolean doDFS(int x, int y, int nextIdx) {
- visited[x][y] = true;
- if (nextIdx == word.length()) {
+
+ private boolean dfs(char[][] board, int x, int y, String word, int idx) {
+ if (idx == word.length()) {
return true;
}
- for (int i = 0; i < 4; ++i) {
- int xi = x + dx[i];
- int yi = y + dy[i];
- if (isValid(xi, yi) && board[xi][yi] == word.charAt(nextIdx) && !visited[xi][yi]) {
- boolean exists = doDFS(xi, yi, nextIdx + 1);
- if (exists) {
- return true;
- }
- }
+ if (x < 0 || y < 0 || x >= board.length || y >= board[0].length || board[x][y] != word.charAt(idx)) {
+ return false;
}
- visited[x][y] = false; // Backtrack
- return false;
+ char temp = board[x][y];
+ board[x][y] = '#';
+
+ boolean found = dfs(board, x + 1, y, word, idx + 1) || dfs(board, x - 1, y, word, idx + 1) || dfs(board, x, y + 1, word, idx + 1) || dfs(board, x, y - 1, word, idx + 1);
+
+ board[x][y] = temp;
+
+ return found;
}
/**
@@ -90,20 +73,21 @@ private boolean doDFS(int x, int y, int nextIdx) {
* @param word The target word to search for in the board.
* @return True if the word exists in the board; false otherwise.
*/
+
public boolean exist(char[][] board, String word) {
- this.board = board;
- this.word = word;
- for (int i = 0; i < board.length; ++i) {
- for (int j = 0; j < board[0].length; ++j) {
- if (board[i][j] == word.charAt(0)) {
- visited = new boolean[board.length][board[0].length];
- boolean exists = doDFS(i, j, 1);
- if (exists) {
- return true;
- }
+
+ int m = board.length;
+ int n = board[0].length;
+
+ // DFS search
+ for (int i = 0; i < m; i++) {
+ for (int j = 0; j < n; j++) {
+ if (board[i][j] == word.charAt(0) && dfs(board, i, j, word, 0)) {
+ return true;
}
}
}
+
return false;
}
}
From 7d57c5720670dc0fd6e37d7bdc41ad053d925f5b Mon Sep 17 00:00:00 2001
From: kvadrik <41710943+kvadrik@users.noreply.github.com>
Date: Sun, 15 Mar 2026 19:44:31 +0200
Subject: [PATCH 57/58] Added quadratic mean (#7315)
* Added quadratic mean
Added a quadratic mean of the given numbers, sqrt ((n1^2+n2^2+...+nk^2)/k).
* Added tests for quadratic mean
* Corrected quadratic mean
* Added comment to quadratic mean
* Corrected quadratic mean tests
* Replaced sqrt by pow
* Error fixed
* Extra whitespace removed
* Extra whitespace removed
* Removed extra white space
* Removed extra white space
---
.../java/com/thealgorithms/maths/Means.java | 22 ++++++++
.../com/thealgorithms/maths/MeansTest.java | 53 ++++++++++++++++++-
2 files changed, 74 insertions(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/maths/Means.java b/src/main/java/com/thealgorithms/maths/Means.java
index 5445a3caebc7..d77eb1d3f661 100644
--- a/src/main/java/com/thealgorithms/maths/Means.java
+++ b/src/main/java/com/thealgorithms/maths/Means.java
@@ -107,6 +107,28 @@ public static Double harmonic(final Iterable numbers) {
return size / sumOfReciprocals;
}
+ /**
+ * Computes the quadratic mean (root mean square) of the given numbers.
+ *
+ * The quadratic mean is calculated as: √[(x₁^2 × x₂^2 × ... × xₙ^2)/n]
+ *
+ *
+ * Example: For numbers [1, 7], the quadratic mean is √[(1^2+7^2)/2] = √25 = 5.0
+ *
+ *
+ * @param numbers the input numbers (must not be empty)
+ * @return the quadratic mean of the input numbers
+ * @throws IllegalArgumentException if the input is empty
+ * @see Quadratic
+ * Mean
+ */
+ public static Double quadratic(final Iterable numbers) {
+ checkIfNotEmpty(numbers);
+ double sumOfSquares = StreamSupport.stream(numbers.spliterator(), false).reduce(0d, (x, y) -> x + y * y);
+ int size = IterableUtils.size(numbers);
+ return Math.pow(sumOfSquares / size, 0.5);
+ }
+
/**
* Validates that the input iterable is not empty.
*
diff --git a/src/test/java/com/thealgorithms/maths/MeansTest.java b/src/test/java/com/thealgorithms/maths/MeansTest.java
index deee0a931910..853fdbea3963 100644
--- a/src/test/java/com/thealgorithms/maths/MeansTest.java
+++ b/src/test/java/com/thealgorithms/maths/MeansTest.java
@@ -172,6 +172,53 @@ void testHarmonicMeanWithLinkedList() {
assertEquals(expected, Means.harmonic(numbers), EPSILON);
}
+ // ========== Quadratic Mean Tests ==========
+
+ @Test
+ void testQuadraticMeanThrowsExceptionForEmptyList() {
+ List numbers = new ArrayList<>();
+ IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> Means.quadratic(numbers));
+ assertTrue(exception.getMessage().contains("Empty list"));
+ }
+
+ @Test
+ void testQuadraticMeanSingleNumber() {
+ LinkedHashSet numbers = new LinkedHashSet<>(Arrays.asList(2.5));
+ assertEquals(2.5, Means.quadratic(numbers), EPSILON);
+ }
+
+ @Test
+ void testQuadraticMeanTwoNumbers() {
+ List numbers = Arrays.asList(1.0, 7.0);
+ assertEquals(5.0, Means.quadratic(numbers), EPSILON);
+ }
+
+ @Test
+ void testQuadraticMeanMultipleNumbers() {
+ Vector numbers = new Vector<>(Arrays.asList(1.0, 2.5, 3.0, 7.5, 10.0));
+ double expected = Math.sqrt(34.5);
+ assertEquals(expected, Means.quadratic(numbers), EPSILON);
+ }
+
+ @Test
+ void testQuadraticMeanThreeNumbers() {
+ List numbers = Arrays.asList(3.0, 6.0, 9.0);
+ double expected = Math.sqrt(42.0);
+ assertEquals(expected, Means.quadratic(numbers), EPSILON);
+ }
+
+ @Test
+ void testQuadraticMeanIdenticalNumbers() {
+ List numbers = Arrays.asList(5.0, 5.0, 5.0);
+ assertEquals(5.0, Means.quadratic(numbers), EPSILON);
+ }
+
+ @Test
+ void testQuadraticMeanWithLinkedList() {
+ LinkedList numbers = new LinkedList<>(Arrays.asList(1.0, 5.0, 11.0));
+ assertEquals(7.0, Means.quadratic(numbers), EPSILON);
+ }
+
// ========== Additional Edge Case Tests ==========
@Test
@@ -198,21 +245,25 @@ void testAllMeansConsistencyForIdenticalValues() {
double arithmetic = Means.arithmetic(numbers);
double geometric = Means.geometric(numbers);
double harmonic = Means.harmonic(numbers);
+ double quadratic = Means.quadratic(numbers);
assertEquals(7.5, arithmetic, EPSILON);
assertEquals(7.5, geometric, EPSILON);
assertEquals(7.5, harmonic, EPSILON);
+ assertEquals(7.5, quadratic, EPSILON);
}
@Test
void testMeansRelationship() {
- // For positive numbers, harmonic mean ≤ geometric mean ≤ arithmetic mean
+ // For positive numbers, harmonic mean ≤ geometric mean ≤ arithmetic mean ≤ quadratic mean
List numbers = Arrays.asList(2.0, 4.0, 8.0);
double arithmetic = Means.arithmetic(numbers);
double geometric = Means.geometric(numbers);
double harmonic = Means.harmonic(numbers);
+ double quadratic = Means.quadratic(numbers);
assertTrue(harmonic <= geometric, "Harmonic mean should be ≤ geometric mean");
assertTrue(geometric <= arithmetic, "Geometric mean should be ≤ arithmetic mean");
+ assertTrue(arithmetic <= quadratic, "Arithmetic mean should be ≤ quadratic mean");
}
}
From af1d9d166522e3904ce60f2303d1ad9d8b462d62 Mon Sep 17 00:00:00 2001
From: Keykyrios
Date: Thu, 19 Mar 2026 00:55:39 +0530
Subject: [PATCH 58/58] feat(strings): add Kasai's algorithm for LCP array
construction (#7324)
* feat(strings): add Kasai's algorithm for LCP array
Implement Kasai's algorithm to compute the Longest Common Prefix (LCP) array in O(N) time given a string and its suffix array. Add KasaiAlgorithm.java and KasaiAlgorithmTest.java.
* style(strings): fix KasaiAlgorithmTest array initialization format for clang-format
---
.../thealgorithms/strings/KasaiAlgorithm.java | 79 +++++++++++++++++++
.../strings/KasaiAlgorithmTest.java | 75 ++++++++++++++++++
2 files changed, 154 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/strings/KasaiAlgorithm.java
create mode 100644 src/test/java/com/thealgorithms/strings/KasaiAlgorithmTest.java
diff --git a/src/main/java/com/thealgorithms/strings/KasaiAlgorithm.java b/src/main/java/com/thealgorithms/strings/KasaiAlgorithm.java
new file mode 100644
index 000000000000..b8b10dcf4538
--- /dev/null
+++ b/src/main/java/com/thealgorithms/strings/KasaiAlgorithm.java
@@ -0,0 +1,79 @@
+package com.thealgorithms.strings;
+
+/**
+ * Kasai's Algorithm for constructing the Longest Common Prefix (LCP) array.
+ *
+ *
+ * The LCP array stores the lengths of the longest common prefixes between
+ * lexicographically adjacent suffixes of a string. Kasai's algorithm computes
+ * this array in O(N) time given the string and its suffix array.
+ *
+ *
+ * @see LCP array - Wikipedia
+ */
+public final class KasaiAlgorithm {
+
+ private KasaiAlgorithm() {
+ }
+
+ /**
+ * Computes the LCP array using Kasai's algorithm.
+ *
+ * @param text the original string
+ * @param suffixArr the suffix array of the string
+ * @return the LCP array of length N, where LCP[i] is the length of the longest
+ * common prefix of the suffixes indexed by suffixArr[i] and suffixArr[i+1].
+ * The last element LCP[N-1] is always 0.
+ * @throws IllegalArgumentException if text or suffixArr is null, or their lengths differ
+ */
+ public static int[] kasai(String text, int[] suffixArr) {
+ if (text == null || suffixArr == null) {
+ throw new IllegalArgumentException("Text and suffix array must not be null.");
+ }
+ int n = text.length();
+ if (suffixArr.length != n) {
+ throw new IllegalArgumentException("Suffix array length must match text length.");
+ }
+ if (n == 0) {
+ return new int[0];
+ }
+
+ // Compute the inverse suffix array
+ // invSuff[i] stores the index of the suffix text.substring(i) in the suffix array
+ int[] invSuff = new int[n];
+ for (int i = 0; i < n; i++) {
+ if (suffixArr[i] < 0 || suffixArr[i] >= n) {
+ throw new IllegalArgumentException("Suffix array contains out-of-bounds index.");
+ }
+ invSuff[suffixArr[i]] = i;
+ }
+
+ int[] lcp = new int[n];
+ int k = 0; // Length of the longest common prefix
+
+ for (int i = 0; i < n; i++) {
+ // Suffix at index i has not a next suffix in suffix array
+ int rank = invSuff[i];
+ if (rank == n - 1) {
+ k = 0;
+ continue;
+ }
+
+ int nextSuffixIndex = suffixArr[rank + 1];
+
+ // Directly match characters to find LCP
+ while (i + k < n && nextSuffixIndex + k < n && text.charAt(i + k) == text.charAt(nextSuffixIndex + k)) {
+ k++;
+ }
+
+ lcp[rank] = k;
+
+ // Delete the starting character from the string
+ if (k > 0) {
+ k--;
+ }
+ }
+
+ return lcp;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/strings/KasaiAlgorithmTest.java b/src/test/java/com/thealgorithms/strings/KasaiAlgorithmTest.java
new file mode 100644
index 000000000000..c22cc77df18a
--- /dev/null
+++ b/src/test/java/com/thealgorithms/strings/KasaiAlgorithmTest.java
@@ -0,0 +1,75 @@
+package com.thealgorithms.strings;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class KasaiAlgorithmTest {
+
+ @Test
+ public void testKasaiBanana() {
+ String text = "banana";
+ // Suffixes:
+ // 0: banana
+ // 1: anana
+ // 2: nana
+ // 3: ana
+ // 4: na
+ // 5: a
+ //
+ // Sorted Suffixes:
+ // 5: a
+ // 3: ana
+ // 1: anana
+ // 0: banana
+ // 4: na
+ // 2: nana
+ int[] suffixArr = {5, 3, 1, 0, 4, 2};
+
+ int[] expectedLcp = {1, 3, 0, 0, 2, 0};
+
+ assertArrayEquals(expectedLcp, KasaiAlgorithm.kasai(text, suffixArr));
+ }
+
+ @Test
+ public void testKasaiAaaa() {
+ String text = "aaaa";
+ // Sorted Suffixes:
+ // 3: a
+ // 2: aa
+ // 1: aaa
+ // 0: aaaa
+ int[] suffixArr = {3, 2, 1, 0};
+ int[] expectedLcp = {1, 2, 3, 0};
+
+ assertArrayEquals(expectedLcp, KasaiAlgorithm.kasai(text, suffixArr));
+ }
+
+ @Test
+ public void testKasaiEmptyString() {
+ assertArrayEquals(new int[0], KasaiAlgorithm.kasai("", new int[0]));
+ }
+
+ @Test
+ public void testKasaiSingleChar() {
+ assertArrayEquals(new int[] {0}, KasaiAlgorithm.kasai("A", new int[] {0}));
+ }
+
+ @Test
+ public void testKasaiNullTextOrSuffixArray() {
+ assertThrows(IllegalArgumentException.class, () -> KasaiAlgorithm.kasai(null, new int[] {0}));
+ assertThrows(IllegalArgumentException.class, () -> KasaiAlgorithm.kasai("A", null));
+ }
+
+ @Test
+ public void testKasaiInvalidSuffixArrayLength() {
+ assertThrows(IllegalArgumentException.class, () -> KasaiAlgorithm.kasai("A", new int[] {0, 1}));
+ }
+
+ @Test
+ public void testKasaiInvalidSuffixArrayIndex() {
+ assertThrows(IllegalArgumentException.class, () -> KasaiAlgorithm.kasai("A", new int[] {1})); // Out of bounds
+ assertThrows(IllegalArgumentException.class, () -> KasaiAlgorithm.kasai("A", new int[] {-1})); // Out of bounds
+ }
+}