Date: Tue, 28 Oct 2025 15:44:59 +0530
Subject: [PATCH 118/272] feat: Add Neville's Algorithm (#6842)
* feat: Add Neville's algorithm for polynomial interpolation
* Update Neville.java
* style: Fix linter formatting issues.
* Handled Div by Zero Case
* Update NevilleTest.java
* Update Neville.java
* Update NevilleTest.java
* Update Neville.java
---
.../java/com/thealgorithms/maths/Neville.java | 61 ++++++++++++++++
.../com/thealgorithms/maths/NevilleTest.java | 69 +++++++++++++++++++
2 files changed, 130 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/maths/Neville.java
create mode 100644 src/test/java/com/thealgorithms/maths/NevilleTest.java
diff --git a/src/main/java/com/thealgorithms/maths/Neville.java b/src/main/java/com/thealgorithms/maths/Neville.java
new file mode 100644
index 000000000000..ca45f2e8a042
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/Neville.java
@@ -0,0 +1,61 @@
+package com.thealgorithms.maths;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * In numerical analysis, Neville's algorithm is an algorithm used for
+ * polynomial interpolation. Given n+1 points, there is a unique polynomial of
+ * degree at most n that passes through all the points. Neville's algorithm
+ * computes the value of this polynomial at a given point.
+ *
+ *
+ * Wikipedia: https://en.wikipedia.org/wiki/Neville%27s_algorithm
+ *
+ * @author Mitrajit Ghorui(KeyKyrios)
+ */
+public final class Neville {
+
+ private Neville() {
+ }
+
+ /**
+ * Evaluates the polynomial that passes through the given points at a
+ * specific x-coordinate.
+ *
+ * @param x The x-coordinates of the points. Must be the same length as y.
+ * @param y The y-coordinates of the points. Must be the same length as x.
+ * @param target The x-coordinate at which to evaluate the polynomial.
+ * @return The interpolated y-value at the target x-coordinate.
+ * @throws IllegalArgumentException if the lengths of x and y arrays are
+ * different, if the arrays are empty, or if x-coordinates are not unique.
+ */
+ public static double interpolate(double[] x, double[] y, double target) {
+ if (x.length != y.length) {
+ throw new IllegalArgumentException("x and y arrays must have the same length.");
+ }
+ if (x.length == 0) {
+ throw new IllegalArgumentException("Input arrays cannot be empty.");
+ }
+
+ // Check for duplicate x-coordinates to prevent division by zero
+ Set seenX = new HashSet<>();
+ for (double val : x) {
+ if (!seenX.add(val)) {
+ throw new IllegalArgumentException("Input x-coordinates must be unique.");
+ }
+ }
+
+ int n = x.length;
+ double[] p = new double[n];
+ System.arraycopy(y, 0, p, 0, n); // Initialize p with y values
+
+ for (int k = 1; k < n; k++) {
+ for (int i = 0; i < n - k; i++) {
+ p[i] = ((target - x[i + k]) * p[i] + (x[i] - target) * p[i + 1]) / (x[i] - x[i + k]);
+ }
+ }
+
+ return p[0];
+ }
+}
diff --git a/src/test/java/com/thealgorithms/maths/NevilleTest.java b/src/test/java/com/thealgorithms/maths/NevilleTest.java
new file mode 100644
index 000000000000..234fb2d65ce4
--- /dev/null
+++ b/src/test/java/com/thealgorithms/maths/NevilleTest.java
@@ -0,0 +1,69 @@
+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 NevilleTest {
+
+ @Test
+ public void testInterpolateLinear() {
+ // Test with a simple linear function y = 2x + 1
+ // Points (0, 1) and (2, 5)
+ double[] x = {0, 2};
+ double[] y = {1, 5};
+ // We want to find y when x = 1, which should be 3
+ double target = 1;
+ double expected = 3.0;
+ assertEquals(expected, Neville.interpolate(x, y, target), 1e-9);
+ }
+
+ @Test
+ public void testInterpolateQuadratic() {
+ // Test with a quadratic function y = x^2
+ // Points (0, 0), (1, 1), (3, 9)
+ double[] x = {0, 1, 3};
+ double[] y = {0, 1, 9};
+ // We want to find y when x = 2, which should be 4
+ double target = 2;
+ double expected = 4.0;
+ assertEquals(expected, Neville.interpolate(x, y, target), 1e-9);
+ }
+
+ @Test
+ public void testInterpolateWithNegativeNumbers() {
+ // Test with y = x^2 - 2x + 1
+ // Points (-1, 4), (0, 1), (2, 1)
+ double[] x = {-1, 0, 2};
+ double[] y = {4, 1, 1};
+ // We want to find y when x = 1, which should be 0
+ double target = 1;
+ double expected = 0.0;
+ assertEquals(expected, Neville.interpolate(x, y, target), 1e-9);
+ }
+
+ @Test
+ public void testMismatchedArrayLengths() {
+ double[] x = {1, 2};
+ double[] y = {1};
+ double target = 1.5;
+ assertThrows(IllegalArgumentException.class, () -> Neville.interpolate(x, y, target));
+ }
+
+ @Test
+ public void testEmptyArrays() {
+ double[] x = {};
+ double[] y = {};
+ double target = 1;
+ assertThrows(IllegalArgumentException.class, () -> Neville.interpolate(x, y, target));
+ }
+
+ @Test
+ public void testDuplicateXCoordinates() {
+ double[] x = {1, 2, 1};
+ double[] y = {5, 8, 3};
+ double target = 1.5;
+ assertThrows(IllegalArgumentException.class, () -> Neville.interpolate(x, y, target));
+ }
+}
From 68746f880f717dfe0ecb5f655da3338bbe179529 Mon Sep 17 00:00:00 2001
From: Keykyrios
Date: Tue, 28 Oct 2025 21:13:54 +0530
Subject: [PATCH 119/272] feat: Add Chebyshev Iteration algorithm (#6963)
* feat: Add Chebyshev Iteration algorithm
* Update ChebyshevIteration.java
* Update ChebyshevIterationTest.java
* Update ChebyshevIteration.java
* Update ChebyshevIterationTest.java
* Update ChebyshevIteration.java
* Update ChebyshevIteration.java
* Update ChebyshevIterationTest.java
* Update ChebyshevIteration.java
* Update ChebyshevIterationTest.java
* Update ChebyshevIterationTest.java
* Update ChebyshevIteration.java
* Update ChebyshevIteration.java
* Update ChebyshevIterationTest.java
* Update ChebyshevIteration.java
* Update ChebyshevIterationTest.java
* Update ChebyshevIteration.java
* Update ChebyshevIterationTest.java
* update
* Update ChebyshevIteration.java
* Update ChebyshevIterationTest.java
* Update ChebyshevIteration.java
* Update ChebyshevIterationTest.java
* Update ChebyshevIteration.java
* Update ChebyshevIterationTest.java
---
.../maths/ChebyshevIteration.java | 181 ++++++++++++++++++
.../maths/ChebyshevIterationTest.java | 105 ++++++++++
2 files changed, 286 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/maths/ChebyshevIteration.java
create mode 100644 src/test/java/com/thealgorithms/maths/ChebyshevIterationTest.java
diff --git a/src/main/java/com/thealgorithms/maths/ChebyshevIteration.java b/src/main/java/com/thealgorithms/maths/ChebyshevIteration.java
new file mode 100644
index 000000000000..bc30f1ba6e7e
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/ChebyshevIteration.java
@@ -0,0 +1,181 @@
+package com.thealgorithms.maths;
+
+/**
+ * In numerical analysis, Chebyshev iteration is an iterative method for solving
+ * systems of linear equations Ax = b. It is designed for systems where the
+ * matrix A is symmetric positive-definite (SPD).
+ *
+ *
+ * This method is a "polynomial acceleration" method, meaning it finds the
+ * optimal polynomial to apply to the residual to accelerate convergence.
+ *
+ *
+ * It requires knowledge of the bounds of the eigenvalues of the matrix A:
+ * m(A) (smallest eigenvalue) and M(A) (largest eigenvalue).
+ *
+ *
+ * Wikipedia: https://en.wikipedia.org/wiki/Chebyshev_iteration
+ *
+ * @author Mitrajit Ghorui(KeyKyrios)
+ */
+public final class ChebyshevIteration {
+
+ private ChebyshevIteration() {
+ }
+
+ /**
+ * Solves the linear system Ax = b using the Chebyshev iteration method.
+ *
+ *
+ * NOTE: The matrix A *must* be symmetric positive-definite (SPD) for this
+ * algorithm to converge.
+ *
+ * @param a The matrix A (must be square, SPD).
+ * @param b The vector b.
+ * @param x0 The initial guess vector.
+ * @param minEigenvalue The smallest eigenvalue of A (m(A)).
+ * @param maxEigenvalue The largest eigenvalue of A (M(A)).
+ * @param maxIterations The maximum number of iterations to perform.
+ * @param tolerance The desired tolerance for the residual norm.
+ * @return The solution vector x.
+ * @throws IllegalArgumentException if matrix/vector dimensions are
+ * incompatible,
+ * if maxIterations <= 0, or if eigenvalues are invalid (e.g., minEigenvalue
+ * <= 0, maxEigenvalue <= minEigenvalue).
+ */
+ public static double[] solve(double[][] a, double[] b, double[] x0, double minEigenvalue, double maxEigenvalue, int maxIterations, double tolerance) {
+ validateInputs(a, b, x0, minEigenvalue, maxEigenvalue, maxIterations, tolerance);
+
+ int n = b.length;
+ double[] x = x0.clone();
+ double[] r = vectorSubtract(b, matrixVectorMultiply(a, x));
+ double[] p = new double[n];
+
+ double d = (maxEigenvalue + minEigenvalue) / 2.0;
+ double c = (maxEigenvalue - minEigenvalue) / 2.0;
+
+ double alpha = 0.0;
+ double alphaPrev = 0.0;
+
+ for (int k = 0; k < maxIterations; k++) {
+ double residualNorm = vectorNorm(r);
+ if (residualNorm < tolerance) {
+ return x; // Solution converged
+ }
+
+ if (k == 0) {
+ alpha = 1.0 / d;
+ System.arraycopy(r, 0, p, 0, n); // p = r
+ } else {
+ double beta = c * alphaPrev / 2.0 * (c * alphaPrev / 2.0);
+ alpha = 1.0 / (d - beta / alphaPrev);
+ double[] pUpdate = scalarMultiply(beta / alphaPrev, p);
+ p = vectorAdd(r, pUpdate); // p = r + (beta / alphaPrev) * p
+ }
+
+ double[] xUpdate = scalarMultiply(alpha, p);
+ x = vectorAdd(x, xUpdate); // x = x + alpha * p
+
+ // Recompute residual for accuracy
+ r = vectorSubtract(b, matrixVectorMultiply(a, x));
+ alphaPrev = alpha;
+ }
+
+ return x; // Return best guess after maxIterations
+ }
+
+ /**
+ * Validates the inputs for the Chebyshev solver.
+ */
+ private static void validateInputs(double[][] a, double[] b, double[] x0, double minEigenvalue, double maxEigenvalue, int maxIterations, double tolerance) {
+ int n = a.length;
+ if (n == 0) {
+ throw new IllegalArgumentException("Matrix A cannot be empty.");
+ }
+ if (n != a[0].length) {
+ throw new IllegalArgumentException("Matrix A must be square.");
+ }
+ if (n != b.length) {
+ throw new IllegalArgumentException("Matrix A and vector b dimensions do not match.");
+ }
+ if (n != x0.length) {
+ throw new IllegalArgumentException("Matrix A and vector x0 dimensions do not match.");
+ }
+ if (minEigenvalue <= 0) {
+ throw new IllegalArgumentException("Smallest eigenvalue must be positive (matrix must be positive-definite).");
+ }
+ if (maxEigenvalue <= minEigenvalue) {
+ throw new IllegalArgumentException("Max eigenvalue must be strictly greater than min eigenvalue.");
+ }
+ if (maxIterations <= 0) {
+ throw new IllegalArgumentException("Max iterations must be positive.");
+ }
+ if (tolerance <= 0) {
+ throw new IllegalArgumentException("Tolerance must be positive.");
+ }
+ }
+
+ // --- Vector/Matrix Helper Methods ---
+ /**
+ * Computes the product of a matrix A and a vector v (Av).
+ */
+ private static double[] matrixVectorMultiply(double[][] a, double[] v) {
+ int n = a.length;
+ double[] result = new double[n];
+ for (int i = 0; i < n; i++) {
+ double sum = 0;
+ for (int j = 0; j < n; j++) {
+ sum += a[i][j] * v[j];
+ }
+ result[i] = sum;
+ }
+ return result;
+ }
+
+ /**
+ * Computes the subtraction of two vectors (v1 - v2).
+ */
+ private static double[] vectorSubtract(double[] v1, double[] v2) {
+ int n = v1.length;
+ double[] result = new double[n];
+ for (int i = 0; i < n; i++) {
+ result[i] = v1[i] - v2[i];
+ }
+ return result;
+ }
+
+ /**
+ * Computes the addition of two vectors (v1 + v2).
+ */
+ private static double[] vectorAdd(double[] v1, double[] v2) {
+ int n = v1.length;
+ double[] result = new double[n];
+ for (int i = 0; i < n; i++) {
+ result[i] = v1[i] + v2[i];
+ }
+ return result;
+ }
+
+ /**
+ * Computes the product of a scalar and a vector (s * v).
+ */
+ private static double[] scalarMultiply(double scalar, double[] v) {
+ int n = v.length;
+ double[] result = new double[n];
+ for (int i = 0; i < n; i++) {
+ result[i] = scalar * v[i];
+ }
+ return result;
+ }
+
+ /**
+ * Computes the L2 norm (Euclidean norm) of a vector.
+ */
+ private static double vectorNorm(double[] v) {
+ double sumOfSquares = 0;
+ for (double val : v) {
+ sumOfSquares += val * val;
+ }
+ return Math.sqrt(sumOfSquares);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/maths/ChebyshevIterationTest.java b/src/test/java/com/thealgorithms/maths/ChebyshevIterationTest.java
new file mode 100644
index 000000000000..d5cf83818fa4
--- /dev/null
+++ b/src/test/java/com/thealgorithms/maths/ChebyshevIterationTest.java
@@ -0,0 +1,105 @@
+package com.thealgorithms.maths;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class ChebyshevIterationTest {
+
+ @Test
+ public void testSolveSimple2x2Diagonal() {
+ double[][] a = {{2, 0}, {0, 1}};
+ double[] b = {2, 2};
+ double[] x0 = {0, 0};
+ double minEig = 1.0;
+ double maxEig = 2.0;
+ int maxIter = 50;
+ double tol = 1e-9;
+ double[] expected = {1.0, 2.0};
+
+ double[] result = ChebyshevIteration.solve(a, b, x0, minEig, maxEig, maxIter, tol);
+ assertArrayEquals(expected, result, 1e-9);
+ }
+
+ @Test
+ public void testSolve2x2Symmetric() {
+ double[][] a = {{4, 1}, {1, 3}};
+ double[] b = {1, 2};
+ double[] x0 = {0, 0};
+ double minEig = (7.0 - Math.sqrt(5.0)) / 2.0;
+ double maxEig = (7.0 + Math.sqrt(5.0)) / 2.0;
+ int maxIter = 100;
+ double tol = 1e-10;
+ double[] expected = {1.0 / 11.0, 7.0 / 11.0};
+
+ double[] result = ChebyshevIteration.solve(a, b, x0, minEig, maxEig, maxIter, tol);
+ assertArrayEquals(expected, result, 1e-9);
+ }
+
+ @Test
+ public void testAlreadyAtSolution() {
+ double[][] a = {{2, 0}, {0, 1}};
+ double[] b = {2, 2};
+ double[] x0 = {1, 2};
+ double minEig = 1.0;
+ double maxEig = 2.0;
+ int maxIter = 10;
+ double tol = 1e-5;
+ double[] expected = {1.0, 2.0};
+
+ double[] result = ChebyshevIteration.solve(a, b, x0, minEig, maxEig, maxIter, tol);
+ assertArrayEquals(expected, result, 0.0);
+ }
+
+ @Test
+ public void testMismatchedDimensionsAB() {
+ double[][] a = {{1, 0}, {0, 1}};
+ double[] b = {1};
+ double[] x0 = {0, 0};
+ assertThrows(IllegalArgumentException.class, () -> ChebyshevIteration.solve(a, b, x0, 1, 2, 10, 1e-5));
+ }
+
+ @Test
+ public void testMismatchedDimensionsAX() {
+ double[][] a = {{1, 0}, {0, 1}};
+ double[] b = {1, 1};
+ double[] x0 = {0};
+ assertThrows(IllegalArgumentException.class, () -> ChebyshevIteration.solve(a, b, x0, 1, 2, 10, 1e-5));
+ }
+
+ @Test
+ public void testNonSquareMatrix() {
+ double[][] a = {{1, 0, 0}, {0, 1, 0}};
+ double[] b = {1, 1};
+ double[] x0 = {0, 0};
+ assertThrows(IllegalArgumentException.class, () -> ChebyshevIteration.solve(a, b, x0, 1, 2, 10, 1e-5));
+ }
+
+ @Test
+ public void testInvalidEigenvalues() {
+ double[][] a = {{1, 0}, {0, 1}};
+ double[] b = {1, 1};
+ double[] x0 = {0, 0};
+ assertThrows(IllegalArgumentException.class, () -> ChebyshevIteration.solve(a, b, x0, 2, 1, 10, 1e-5));
+ assertThrows(IllegalArgumentException.class, () -> ChebyshevIteration.solve(a, b, x0, 1, 1, 10, 1e-5));
+ }
+
+ @Test
+ public void testNonPositiveDefinite() {
+ double[][] a = {{1, 0}, {0, 1}};
+ double[] b = {1, 1};
+ double[] x0 = {0, 0};
+ assertThrows(IllegalArgumentException.class, () -> ChebyshevIteration.solve(a, b, x0, 0, 1, 10, 1e-5));
+ assertThrows(IllegalArgumentException.class, () -> ChebyshevIteration.solve(a, b, x0, -1, 1, 10, 1e-5));
+ }
+
+ @Test
+ public void testInvalidIterationCount() {
+ double[][] a = {{1, 0}, {0, 1}};
+ double[] b = {1, 1};
+ double[] x0 = {0, 0};
+ assertThrows(IllegalArgumentException.class, () -> ChebyshevIteration.solve(a, b, x0, 1, 2, 0, 1e-5));
+ assertThrows(IllegalArgumentException.class, () -> ChebyshevIteration.solve(a, b, x0, 1, 2, -1, 1e-5));
+ }
+}
From bb6385e756a0159a29655c745682e95ca7b41ada Mon Sep 17 00:00:00 2001
From: sairamsharan <143504336+sairamsharan@users.noreply.github.com>
Date: Wed, 29 Oct 2025 14:38:05 +0530
Subject: [PATCH 120/272] feat: Add Stoer-Wagner Algorithm for Minimum Cut
(#6752)
* feat: Add Stoer-Wagner Algorithm for Minimum Cut
* fix: Correct Stoer-Wagner implementation
* fix: Remove unused import
* fix: Apply clang-format
---
.../com/thealgorithms/graph/StoerWagner.java | 78 +++++++++++++++++++
.../thealgorithms/graph/StoerWagnerTest.java | 64 +++++++++++++++
2 files changed, 142 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/graph/StoerWagner.java
create mode 100644 src/test/java/com/thealgorithms/graph/StoerWagnerTest.java
diff --git a/src/main/java/com/thealgorithms/graph/StoerWagner.java b/src/main/java/com/thealgorithms/graph/StoerWagner.java
new file mode 100644
index 000000000000..b204834c431a
--- /dev/null
+++ b/src/main/java/com/thealgorithms/graph/StoerWagner.java
@@ -0,0 +1,78 @@
+package com.thealgorithms.graph;
+
+/**
+ * An implementation of the Stoer-Wagner algorithm to find the global minimum cut of an undirected, weighted graph.
+ * A minimum cut is a partition of the graph's vertices into two disjoint sets with the minimum possible edge weight
+ * sum connecting the two sets.
+ *
+ * Wikipedia: https://en.wikipedia.org/wiki/Stoer%E2%80%93Wagner_algorithm
+ * Time Complexity: O(V^3) where V is the number of vertices.
+ */
+public class StoerWagner {
+
+ /**
+ * Finds the minimum cut in the given undirected, weighted graph.
+ *
+ * @param graph An adjacency matrix representing the graph. graph[i][j] is the weight of the edge between i and j.
+ * @return The weight of the minimum cut.
+ */
+ public int findMinCut(int[][] graph) {
+ int n = graph.length;
+ if (n < 2) {
+ return 0;
+ }
+
+ int[][] currentGraph = new int[n][n];
+ for (int i = 0; i < n; i++) {
+ System.arraycopy(graph[i], 0, currentGraph[i], 0, n);
+ }
+
+ int minCut = Integer.MAX_VALUE;
+ boolean[] merged = new boolean[n];
+
+ for (int phase = 0; phase < n - 1; phase++) {
+ boolean[] inSetA = new boolean[n];
+ int[] weights = new int[n];
+ int prev = -1;
+ int last = -1;
+
+ for (int i = 0; i < n - phase; i++) {
+ int maxWeight = -1;
+ int currentVertex = -1;
+
+ for (int j = 0; j < n; j++) {
+ if (!merged[j] && !inSetA[j] && weights[j] > maxWeight) {
+ maxWeight = weights[j];
+ currentVertex = j;
+ }
+ }
+
+ if (currentVertex == -1) {
+ // This can happen if the graph is disconnected.
+ return 0;
+ }
+
+ prev = last;
+ last = currentVertex;
+ inSetA[last] = true;
+
+ for (int j = 0; j < n; j++) {
+ if (!merged[j] && !inSetA[j]) {
+ weights[j] += currentGraph[last][j];
+ }
+ }
+ }
+
+ minCut = Math.min(minCut, weights[last]);
+
+ // Merge 'last' vertex into 'prev' vertex
+ for (int i = 0; i < n; i++) {
+ currentGraph[prev][i] += currentGraph[last][i];
+ currentGraph[i][prev] = currentGraph[prev][i];
+ }
+ merged[last] = true;
+ }
+
+ return minCut;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/graph/StoerWagnerTest.java b/src/test/java/com/thealgorithms/graph/StoerWagnerTest.java
new file mode 100644
index 000000000000..894d99687d1d
--- /dev/null
+++ b/src/test/java/com/thealgorithms/graph/StoerWagnerTest.java
@@ -0,0 +1,64 @@
+package com.thealgorithms.graph;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the StoerWagner global minimum cut algorithm.
+ *
+ * These tests verify correctness of the implementation across
+ * several graph configurations: simple, complete, disconnected,
+ * and small edge cases.
+ */
+public class StoerWagnerTest {
+
+ @Test
+ public void testSimpleGraph() {
+ int[][] graph = {{0, 3, 2, 0}, {3, 0, 1, 4}, {2, 1, 0, 5}, {0, 4, 5, 0}};
+ StoerWagner algo = new StoerWagner();
+ assertEquals(5, algo.findMinCut(graph)); // Correct minimum cut = 5
+ }
+
+ @Test
+ public void testTriangleGraph() {
+ int[][] graph = {{0, 2, 3}, {2, 0, 4}, {3, 4, 0}};
+ StoerWagner algo = new StoerWagner();
+ assertEquals(5, algo.findMinCut(graph)); // min cut = 5
+ }
+
+ @Test
+ public void testDisconnectedGraph() {
+ int[][] graph = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
+ StoerWagner algo = new StoerWagner();
+ assertEquals(0, algo.findMinCut(graph)); // Disconnected graph => cut = 0
+ }
+
+ @Test
+ public void testCompleteGraph() {
+ int[][] graph = {{0, 1, 1, 1}, {1, 0, 1, 1}, {1, 1, 0, 1}, {1, 1, 1, 0}};
+ StoerWagner algo = new StoerWagner();
+ assertEquals(3, algo.findMinCut(graph)); // Each vertex connected to all others
+ }
+
+ @Test
+ public void testSingleVertex() {
+ int[][] graph = {{0}};
+ StoerWagner algo = new StoerWagner();
+ assertEquals(0, algo.findMinCut(graph)); // Only one vertex
+ }
+
+ @Test
+ public void testTwoVertices() {
+ int[][] graph = {{0, 7}, {7, 0}};
+ StoerWagner algo = new StoerWagner();
+ assertEquals(7, algo.findMinCut(graph)); // Only one edge, cut weight = 7
+ }
+
+ @Test
+ public void testSquareGraphWithDiagonal() {
+ int[][] graph = {{0, 2, 0, 2}, {2, 0, 3, 0}, {0, 3, 0, 4}, {2, 0, 4, 0}};
+ StoerWagner algo = new StoerWagner();
+ assertEquals(4, algo.findMinCut(graph)); // verified manually
+ }
+}
From dfd8d6993fe85b9913eb314c031c85fddb816ae5 Mon Sep 17 00:00:00 2001
From: JonathanButterworth
<149101933+JonathanButterworth@users.noreply.github.com>
Date: Thu, 30 Oct 2025 17:26:22 -0400
Subject: [PATCH 121/272] Added surface area calculation for pyramid (#6853)
Co-authored-by: JonathanButterworth
---
.../java/com/thealgorithms/maths/Area.java | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/src/main/java/com/thealgorithms/maths/Area.java b/src/main/java/com/thealgorithms/maths/Area.java
index 7a06fd5e5fa0..a34ad6b01ab5 100644
--- a/src/main/java/com/thealgorithms/maths/Area.java
+++ b/src/main/java/com/thealgorithms/maths/Area.java
@@ -48,6 +48,25 @@ public static double surfaceAreaSphere(final double radius) {
return 4 * Math.PI * radius * radius;
}
+ /**
+ * Calculate the surface area of a pyramid with a square base.
+ *
+ * @param sideLength side length of the square base
+ * @param slantHeight slant height of the pyramid
+ * @return surface area of the given pyramid
+ */
+ public static double surfaceAreaPyramid(final double sideLength, final double slantHeight) {
+ if (sideLength <= 0) {
+ throw new IllegalArgumentException("Must be a positive sideLength");
+ }
+ if (slantHeight <= 0) {
+ throw new IllegalArgumentException("Must be a positive slantHeight");
+ }
+ double baseArea = sideLength * sideLength;
+ double lateralSurfaceArea = 2 * sideLength * slantHeight;
+ return baseArea + lateralSurfaceArea;
+ }
+
/**
* Calculate the area of a rectangle.
*
From bf8cc61254b7909ef184c0b6da32f7f862afab7a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 1 Nov 2025 10:23:35 +0100
Subject: [PATCH 122/272] chore(deps): bump org.junit:junit-bom from 6.0.0 to
6.0.1 (#7019)
Bumps [org.junit:junit-bom](https://github.com/junit-team/junit-framework) from 6.0.0 to 6.0.1.
- [Release notes](https://github.com/junit-team/junit-framework/releases)
- [Commits](https://github.com/junit-team/junit-framework/compare/r6.0.0...r6.0.1)
---
updated-dependencies:
- dependency-name: org.junit:junit-bom
dependency-version: 6.0.1
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index b7ca85e1407c..825d86f8b239 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,7 +20,7 @@
org.junit
junit-bom
- 6.0.0
+ 6.0.1
pom
import
From 08374248e9cee8780cb6dee9524bcaaef708aa9b Mon Sep 17 00:00:00 2001
From: Priyanshu Kumar Singh
Date: Sat, 1 Nov 2025 14:58:44 +0530
Subject: [PATCH 123/272] [FEAT] Add Coulomb's Law for electrostatics (#7017)
Co-authored-by: Priyanshu1303d
---
.../thealgorithms/maths/JugglerSequence.java | 2 +-
.../thealgorithms/physics/CoulombsLaw.java | 80 ++++++++++++++
.../physics/CoulombsLawTest.java | 100 ++++++++++++++++++
3 files changed, 181 insertions(+), 1 deletion(-)
create mode 100644 src/main/java/com/thealgorithms/physics/CoulombsLaw.java
create mode 100644 src/test/java/com/thealgorithms/physics/CoulombsLawTest.java
diff --git a/src/main/java/com/thealgorithms/maths/JugglerSequence.java b/src/main/java/com/thealgorithms/maths/JugglerSequence.java
index 702310a1f295..a459b4b6d4bb 100644
--- a/src/main/java/com/thealgorithms/maths/JugglerSequence.java
+++ b/src/main/java/com/thealgorithms/maths/JugglerSequence.java
@@ -43,7 +43,7 @@ public static void jugglerSequence(int inputNumber) {
seq.add(n + "");
}
String res = String.join(",", seq);
- System.out.println(res);
+ System.out.print(res + "\n");
}
// Driver code
diff --git a/src/main/java/com/thealgorithms/physics/CoulombsLaw.java b/src/main/java/com/thealgorithms/physics/CoulombsLaw.java
new file mode 100644
index 000000000000..3a3ad3e0d223
--- /dev/null
+++ b/src/main/java/com/thealgorithms/physics/CoulombsLaw.java
@@ -0,0 +1,80 @@
+package com.thealgorithms.physics;
+
+/**
+ * Implements Coulomb's Law for electrostatics.
+ * Provides simple static methods to calculate electrostatic force and circular orbit velocity.
+ *
+ * @author [Priyanshu Singh](https://github.com/Priyanshu1303d)
+ * @see Wikipedia
+ */
+public final class CoulombsLaw {
+
+ /** Coulomb's constant in N·m²/C² */
+ public static final double COULOMBS_CONSTANT = 8.9875517923e9;
+
+ /**
+ * Private constructor to prevent instantiation of this utility class.
+ */
+ private CoulombsLaw() {
+ }
+
+ /**
+ * Calculates the electrostatic force vector exerted by one charge on another.
+ * The returned vector is the force *on* the second charge (q2).
+ *
+ * @param q1 Charge of the first particle (in Coulombs).
+ * @param x1 X-position of the first particle (m).
+ * @param y1 Y-position of the first particle (m).
+ * @param q2 Charge of the second particle (in Coulombs).
+ * @param x2 X-position of the second particle (m).
+ * @param y2 Y-position of the second particle (m).
+ * @return A double array `[fx, fy]` representing the force vector on the second charge.
+ */
+ public static double[] calculateForceVector(double q1, double x1, double y1, double q2, double x2, double y2) {
+ // Vector from 1 to 2
+ double dx = x2 - x1;
+ double dy = y2 - y1;
+ double distanceSq = dx * dx + dy * dy;
+
+ // If particles are at the same position, force is zero to avoid division by zero.
+ if (distanceSq == 0) {
+ return new double[] {0, 0};
+ }
+
+ double distance = Math.sqrt(distanceSq);
+ // Force magnitude: k * (q1 * q2) / r^2
+ // A positive result is repulsive (pushes q2 away from q1).
+ // A negative result is attractive (pulls q2 toward q1).
+ double forceMagnitude = COULOMBS_CONSTANT * q1 * q2 / distanceSq;
+
+ // Calculate the components of the force vector
+ // (dx / distance) is the unit vector pointing from 1 to 2.
+ double fx = forceMagnitude * (dx / distance);
+ double fy = forceMagnitude * (dy / distance);
+
+ return new double[] {fx, fy};
+ }
+
+ /**
+ * Calculates the speed required for a stable circular orbit of a charged particle
+ * around a central charge (e.g., an electron orbiting a nucleus).
+ *
+ * @param centralCharge The charge of the central body (in Coulombs).
+ * @param orbitingCharge The charge of the orbiting body (in Coulombs).
+ * @param orbitingMass The mass of the orbiting body (in kg).
+ * @param radius The radius of the orbit (in m).
+ * @return The orbital speed (in m/s).
+ * @throws IllegalArgumentException if mass or radius are not positive.
+ */
+ public static double calculateCircularOrbitVelocity(double centralCharge, double orbitingCharge, double orbitingMass, double radius) {
+ if (orbitingMass <= 0 || radius <= 0) {
+ throw new IllegalArgumentException("Orbiting mass and radius must be positive.");
+ }
+
+ // We only need the magnitude of the force, which is always positive.
+ double forceMagnitude = Math.abs(COULOMBS_CONSTANT * centralCharge * orbitingCharge) / (radius * radius);
+
+ // F_c = m * v^2 / r => v = sqrt(F_c * r / m)
+ return Math.sqrt(forceMagnitude * radius / orbitingMass);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/physics/CoulombsLawTest.java b/src/test/java/com/thealgorithms/physics/CoulombsLawTest.java
new file mode 100644
index 000000000000..9829e703bd10
--- /dev/null
+++ b/src/test/java/com/thealgorithms/physics/CoulombsLawTest.java
@@ -0,0 +1,100 @@
+package com.thealgorithms.physics;
+
+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.DisplayName;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the CoulombsLaw utility class.
+ */
+final class CoulombsLawTest {
+
+ // A small tolerance (delta) for comparing floating-point numbers
+ private static final double DELTA = 1e-9;
+ private static final double K = CoulombsLaw.COULOMBS_CONSTANT;
+
+ @Test
+ @DisplayName("Test repulsive force between two charges on the x-axis")
+ void testSimpleRepulsiveForce() {
+ // Two positive 1C charges, 1 meter apart.
+ // Force on q2 should be F = K*1*1 / 1^2 = K, directed away from q1 (positive x)
+ double[] forceOnB = CoulombsLaw.calculateForceVector(1.0, 0, 0, 1.0, 1, 0);
+ assertArrayEquals(new double[] {K, 0.0}, forceOnB, DELTA);
+
+ // Force on q1 should be equal and opposite (negative x)
+ double[] forceOnA = CoulombsLaw.calculateForceVector(1.0, 1, 0, 1.0, 0, 0);
+ assertArrayEquals(new double[] {-K, 0.0}, forceOnA, DELTA);
+ }
+
+ @Test
+ @DisplayName("Test attractive force between two charges on the x-axis")
+ void testSimpleAttractiveForce() {
+ // One positive 1C, one negative -1C, 1 meter apart.
+ // Force on q2 should be F = K*1*(-1) / 1^2 = -K, directed toward q1 (negative x)
+ double[] forceOnB = CoulombsLaw.calculateForceVector(1.0, 0, 0, -1.0, 1, 0);
+ assertArrayEquals(new double[] {-K, 0.0}, forceOnB, DELTA);
+ }
+
+ @Test
+ @DisplayName("Test electrostatic force in a 2D plane (repulsive)")
+ void test2DRepulsiveForce() {
+ // q1 at (0,0) with charge +2C
+ // q2 at (3,4) with charge +1C
+ // Distance is 5 meters.
+ double magnitude = K * 2.0 * 1.0 / 25.0; // 2K/25
+ // Unit vector from 1 to 2 is (3/5, 4/5)
+ double expectedFx = magnitude * (3.0 / 5.0); // 6K / 125
+ double expectedFy = magnitude * (4.0 / 5.0); // 8K / 125
+
+ double[] forceOnB = CoulombsLaw.calculateForceVector(2.0, 0, 0, 1.0, 3, 4);
+ assertArrayEquals(new double[] {expectedFx, expectedFy}, forceOnB, DELTA);
+ }
+
+ @Test
+ @DisplayName("Test overlapping charges should result in zero force")
+ void testOverlappingCharges() {
+ double[] force = CoulombsLaw.calculateForceVector(1.0, 1.5, -2.5, -1.0, 1.5, -2.5);
+ assertArrayEquals(new double[] {0.0, 0.0}, force, DELTA);
+ }
+
+ @Test
+ @DisplayName("Test circular orbit velocity with simple values")
+ void testCircularOrbitVelocity() {
+ // v = sqrt( (K*1*1 / 1^2) * 1 / 1 ) = sqrt(K)
+ double velocity = CoulombsLaw.calculateCircularOrbitVelocity(1.0, 1.0, 1.0, 1.0);
+ assertEquals(Math.sqrt(K), velocity, DELTA);
+ }
+
+ @Test
+ @DisplayName("Test orbital velocity for a Hydrogen atom (Bohr model)")
+ void testHydrogenAtomVelocity() {
+ // Charge of a proton
+ double protonCharge = 1.602176634e-19;
+ // Charge of an electron
+ double electronCharge = -1.602176634e-19;
+ // Mass of an electron
+ double electronMass = 9.1093837e-31;
+ // Bohr radius (avg distance)
+ double bohrRadius = 5.29177e-11;
+
+ double expectedVelocity = 2.1876917e6;
+
+ double velocity = CoulombsLaw.calculateCircularOrbitVelocity(protonCharge, electronCharge, electronMass, bohrRadius);
+ // Use a wider delta for this real-world calculation
+ assertEquals(expectedVelocity, velocity, 1.0);
+ }
+
+ @Test
+ @DisplayName("Test invalid inputs for orbital velocity throw exception")
+ void testInvalidOrbitalVelocityInputs() {
+ // Non-positive mass
+ assertThrows(IllegalArgumentException.class, () -> CoulombsLaw.calculateCircularOrbitVelocity(1, 1, 0, 100));
+ assertThrows(IllegalArgumentException.class, () -> CoulombsLaw.calculateCircularOrbitVelocity(1, 1, -1, 100));
+ // Non-positive radius
+ assertThrows(IllegalArgumentException.class, () -> CoulombsLaw.calculateCircularOrbitVelocity(1, 1, 1, 0));
+ assertThrows(IllegalArgumentException.class, () -> CoulombsLaw.calculateCircularOrbitVelocity(1, 1, 1, -100));
+ }
+}
From d717ca4fd5d2bd151359964b5075cf785a080641 Mon Sep 17 00:00:00 2001
From: sharan <143504336+sairamsharan@users.noreply.github.com>
Date: Sun, 2 Nov 2025 16:06:10 +0530
Subject: [PATCH 124/272] feat: Add Hierholzer's Algorithm for Eulerian
Circuits (#6726)
* feat: Add Hierholzer's Algorithm for Eulerian Circuits
* fix: Add more test cases to improve code coverage
* feat: Add Hierholzer's Algorithm for Eulerian Circuits
* fix: Apply clang-format after merge
* fix: Apply all formatting, style, and efficiency fixes
* docs: Apply feedback and improve Javadoc
* docs: Add Hierholzer's Algorithm to DIRECTORY.md
---
DIRECTORY.md | 1 +
.../graph/HierholzerAlgorithm.java | 140 ++++++++++++++++++
.../graph/HierholzerAlgorithmTest.java | 60 ++++++++
3 files changed, 201 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/graph/HierholzerAlgorithm.java
create mode 100644 src/test/java/com/thealgorithms/graph/HierholzerAlgorithmTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 47833a3f59f2..eca2453fad0f 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -173,6 +173,7 @@
- 📄 [FordFulkerson](src/main/java/com/thealgorithms/datastructures/graphs/FordFulkerson.java)
- 📄 [Graphs](src/main/java/com/thealgorithms/datastructures/graphs/Graphs.java)
- 📄 [HamiltonianCycle](src/main/java/com/thealgorithms/datastructures/graphs/HamiltonianCycle.java)
+ - 📄 [HierholzerAlgorithm](src/main/java/com/thealgorithms/graph/HierholzerAlgorithm.java)
- 📄 [JohnsonsAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithm.java)
- 📄 [KahnsAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/KahnsAlgorithm.java)
- 📄 [Kosaraju](src/main/java/com/thealgorithms/datastructures/graphs/Kosaraju.java)
diff --git a/src/main/java/com/thealgorithms/graph/HierholzerAlgorithm.java b/src/main/java/com/thealgorithms/graph/HierholzerAlgorithm.java
new file mode 100644
index 000000000000..a804f77d7fa6
--- /dev/null
+++ b/src/main/java/com/thealgorithms/graph/HierholzerAlgorithm.java
@@ -0,0 +1,140 @@
+package com.thealgorithms.graph;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+/**
+ * Implementation of Hierholzer's algorithm to find an Eulerian Circuit in an undirected graph.
+ *
+ * An Eulerian circuit is a trail in a graph that visits every edge exactly once,
+ * starting and ending at the same vertex. This algorithm finds such a circuit if one exists.
+ *
+ *
+ * This implementation is designed for an undirected graph. For a valid Eulerian
+ * circuit to exist, the graph must satisfy two conditions:
+ *
+ * - All vertices with a non-zero degree must be part of a single connected component.
+ * - Every vertex must have an even degree (an even number of edges connected to it).
+ *
+ *
+ *
+ * The algorithm runs in O(E + V) time, where E is the number of edges and V is the number of vertices.
+ * The graph is represented by a Map where keys are vertices and values are a LinkedList of adjacent vertices.
+ *
+ *
+ * @see Wikipedia: Hierholzer's algorithm
+ */
+public final class HierholzerAlgorithm {
+
+ private final Map> graph;
+
+ public HierholzerAlgorithm(Map> graph) {
+ this.graph = (graph == null) ? new HashMap<>() : graph;
+ }
+
+ public boolean hasEulerianCircuit() {
+ if (graph.isEmpty()) {
+ return true;
+ }
+
+ for (List neighbors : graph.values()) {
+ if (neighbors.size() % 2 != 0) {
+ return false;
+ }
+ }
+
+ return isCoherentlyConnected();
+ }
+
+ public List findEulerianCircuit() {
+ if (!hasEulerianCircuit()) {
+ return Collections.emptyList();
+ }
+
+ Map> tempGraph = new HashMap<>();
+ for (Map.Entry> entry : graph.entrySet()) {
+ tempGraph.put(entry.getKey(), new LinkedList<>(entry.getValue()));
+ }
+
+ Stack currentPath = new Stack<>();
+ LinkedList circuit = new LinkedList<>();
+
+ int startVertex = -1;
+ for (Map.Entry> entry : tempGraph.entrySet()) {
+ if (!entry.getValue().isEmpty()) {
+ startVertex = entry.getKey();
+ break;
+ }
+ }
+
+ if (startVertex == -1) {
+ if (graph.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return Collections.singletonList(graph.keySet().iterator().next());
+ }
+
+ currentPath.push(startVertex);
+
+ while (!currentPath.isEmpty()) {
+ int currentVertex = currentPath.peek();
+
+ if (tempGraph.containsKey(currentVertex) && !tempGraph.get(currentVertex).isEmpty()) {
+ int nextVertex = tempGraph.get(currentVertex).pollFirst();
+ tempGraph.get(nextVertex).remove(Integer.valueOf(currentVertex));
+ currentPath.push(nextVertex);
+ } else {
+ circuit.addFirst(currentVertex);
+ currentPath.pop();
+ }
+ }
+
+ return circuit;
+ }
+
+ private boolean isCoherentlyConnected() {
+ if (graph.isEmpty()) {
+ return true;
+ }
+
+ Set visited = new HashSet<>();
+ int startNode = -1;
+
+ for (Map.Entry> entry : graph.entrySet()) {
+ if (!entry.getValue().isEmpty()) {
+ startNode = entry.getKey();
+ break;
+ }
+ }
+
+ if (startNode == -1) {
+ return true;
+ }
+
+ dfs(startNode, visited);
+
+ for (Map.Entry> entry : graph.entrySet()) {
+ if (!entry.getValue().isEmpty() && !visited.contains(entry.getKey())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void dfs(int u, Set visited) {
+ visited.add(u);
+ if (graph.containsKey(u)) {
+ for (int v : graph.get(u)) {
+ if (!visited.contains(v)) {
+ dfs(v, visited);
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/thealgorithms/graph/HierholzerAlgorithmTest.java b/src/test/java/com/thealgorithms/graph/HierholzerAlgorithmTest.java
new file mode 100644
index 000000000000..4dadb206d134
--- /dev/null
+++ b/src/test/java/com/thealgorithms/graph/HierholzerAlgorithmTest.java
@@ -0,0 +1,60 @@
+package com.thealgorithms.graph;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+
+public class HierholzerAlgorithmTest {
+
+ @Test
+ public void testFindsEulerianCircuitInSimpleTriangleGraph() {
+ Map> graph = new HashMap<>();
+ graph.put(0, new LinkedList<>(Arrays.asList(1, 2)));
+ graph.put(1, new LinkedList<>(Arrays.asList(0, 2)));
+ graph.put(2, new LinkedList<>(Arrays.asList(0, 1)));
+ HierholzerAlgorithm algorithm = new HierholzerAlgorithm(graph);
+ assertTrue(algorithm.hasEulerianCircuit());
+ List circuit = algorithm.findEulerianCircuit();
+ assertEquals(4, circuit.size());
+ assertEquals(circuit.get(0), circuit.get(circuit.size() - 1));
+ }
+
+ @Test
+ public void testFailsForGraphWithOddDegreeVertices() {
+ Map> graph = new HashMap<>();
+ graph.put(0, new LinkedList<>(Collections.singletonList(1)));
+ graph.put(1, new LinkedList<>(Collections.singletonList(0)));
+ HierholzerAlgorithm algorithm = new HierholzerAlgorithm(graph);
+ assertFalse(algorithm.hasEulerianCircuit());
+ assertTrue(algorithm.findEulerianCircuit().isEmpty());
+ }
+
+ @Test
+ public void testFailsForDisconnectedGraph() {
+ Map> graph = new HashMap<>();
+ graph.put(0, new LinkedList<>(Arrays.asList(1, 2)));
+ graph.put(1, new LinkedList<>(Arrays.asList(0, 2)));
+ graph.put(2, new LinkedList<>(Arrays.asList(0, 1)));
+ graph.put(3, new LinkedList<>(Arrays.asList(4, 5)));
+ graph.put(4, new LinkedList<>(Arrays.asList(3, 5)));
+ graph.put(5, new LinkedList<>(Arrays.asList(3, 4)));
+ HierholzerAlgorithm algorithm = new HierholzerAlgorithm(graph);
+ assertFalse(algorithm.hasEulerianCircuit());
+ }
+
+ @Test
+ public void testHandlesEmptyGraph() {
+ Map> graph = new HashMap<>();
+ HierholzerAlgorithm algorithm = new HierholzerAlgorithm(graph);
+ assertTrue(algorithm.hasEulerianCircuit());
+ assertTrue(algorithm.findEulerianCircuit().isEmpty());
+ }
+}
From 82ff14c36e80e975970dd61ac9fa193a192fa973 Mon Sep 17 00:00:00 2001
From: Yajunesh MR <145507360+Yajunesh@users.noreply.github.com>
Date: Tue, 4 Nov 2025 02:42:24 +0530
Subject: [PATCH 125/272] feat: Add BitRotate utility for circular bit
rotations (#7011)
* feat: Add BitRotate utility for circular bit rotations
* feat: Add BitRotate utility for circular bit rotations
* feat: Add BitRotate utility for circular bit rotations
* fix: Remove trailing spaces and add newline at EOF
---------
Co-authored-by: Yajunesh M R
---
.../bitmanipulation/BitRotate.java | 83 +++++++
.../bitmanipulation/BitRotateTest.java | 205 ++++++++++++++++++
2 files changed, 288 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/bitmanipulation/BitRotate.java
create mode 100644 src/test/java/com/thealgorithms/bitmanipulation/BitRotateTest.java
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/BitRotate.java b/src/main/java/com/thealgorithms/bitmanipulation/BitRotate.java
new file mode 100644
index 000000000000..226e09e78d1f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/BitRotate.java
@@ -0,0 +1,83 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Utility class for performing circular bit rotations on 32-bit integers.
+ * Bit rotation is a circular shift operation where bits shifted out on one end
+ * are reinserted on the opposite end.
+ *
+ * This class provides methods for both left and right circular rotations,
+ * supporting only 32-bit integer operations with proper shift normalization
+ * and error handling.
+ *
+ * @see Bit Rotation
+ */
+public final class BitRotate {
+
+ /**
+ * Private constructor to prevent instantiation.
+ * This is a utility class with only static methods.
+ */
+ private BitRotate() {
+ throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
+ }
+
+ /**
+ * Performs a circular left rotation (left shift) on a 32-bit integer.
+ * Bits shifted out from the left side are inserted on the right side.
+ *
+ * @param value the 32-bit integer value to rotate
+ * @param shift the number of positions to rotate left (must be non-negative)
+ * @return the result of left rotating the value by the specified shift amount
+ * @throws IllegalArgumentException if shift is negative
+ *
+ * @example
+ * // Binary: 10000000 00000000 00000000 00000001
+ * rotateLeft(0x80000001, 1)
+ * // Returns: 3 (binary: 00000000 00000000 00000000 00000011)
+ */
+ public static int rotateLeft(int value, int shift) {
+ if (shift < 0) {
+ throw new IllegalArgumentException("Shift amount cannot be negative: " + shift);
+ }
+
+ // Normalize shift to the range [0, 31] using modulo 32
+ shift = shift % 32;
+
+ if (shift == 0) {
+ return value;
+ }
+
+ // Left rotation: (value << shift) | (value >>> (32 - shift))
+ return (value << shift) | (value >>> (32 - shift));
+ }
+
+ /**
+ * Performs a circular right rotation (right shift) on a 32-bit integer.
+ * Bits shifted out from the right side are inserted on the left side.
+ *
+ * @param value the 32-bit integer value to rotate
+ * @param shift the number of positions to rotate right (must be non-negative)
+ * @return the result of right rotating the value by the specified shift amount
+ * @throws IllegalArgumentException if shift is negative
+ *
+ * @example
+ * // Binary: 00000000 00000000 00000000 00000011
+ * rotateRight(3, 1)
+ * // Returns: -2147483647 (binary: 10000000 00000000 00000000 00000001)
+ */
+ public static int rotateRight(int value, int shift) {
+ if (shift < 0) {
+ throw new IllegalArgumentException("Shift amount cannot be negative: " + shift);
+ }
+
+ // Normalize shift to the range [0, 31] using modulo 32
+ shift = shift % 32;
+
+ if (shift == 0) {
+ return value;
+ }
+
+ // Right rotation: (value >>> shift) | (value << (32 - shift))
+ return (value >>> shift) | (value << (32 - shift));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/bitmanipulation/BitRotateTest.java b/src/test/java/com/thealgorithms/bitmanipulation/BitRotateTest.java
new file mode 100644
index 000000000000..0595ae5a73e1
--- /dev/null
+++ b/src/test/java/com/thealgorithms/bitmanipulation/BitRotateTest.java
@@ -0,0 +1,205 @@
+package com.thealgorithms.bitmanipulation;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for BitRotate class covering typical, boundary, and edge cases.
+ * Tests verify correct behavior for 32-bit circular bit rotations.
+ *
+ * @author Yajunesh
+ */
+public class BitRotateTest {
+
+ // ===== rotateLeft Tests =====
+
+ @Test
+ public void testRotateLeftBasic() {
+ // Basic left rotation
+ assertEquals(0b00000000_00000000_00000000_00000010, BitRotate.rotateLeft(1, 1));
+ assertEquals(0b00000000_00000000_00000000_00000100, BitRotate.rotateLeft(1, 2));
+ assertEquals(0b00000000_00000000_00000000_00001000, BitRotate.rotateLeft(1, 3));
+ }
+
+ @Test
+ public void testRotateLeftWithCarry() {
+ // Test bits carrying from left to right
+ // Binary: 10000000_00000000_00000000_00000001
+ int value = 0x80000001;
+ // After left rotate by 1: 00000000_00000000_00000000_00000011
+ assertEquals(3, BitRotate.rotateLeft(value, 1));
+
+ // Binary: 11000000_00000000_00000000_00000000
+ value = 0xC0000000;
+ // After left rotate by 1: 10000000_00000000_00000000_00000001
+ assertEquals(0x80000001, BitRotate.rotateLeft(value, 1));
+ }
+
+ @Test
+ public void testRotateLeftShift32() {
+ // Shift of 32 should be same as shift of 0 (modulo behavior)
+ int value = 0x12345678;
+ assertEquals(value, BitRotate.rotateLeft(value, 32));
+ assertEquals(value, BitRotate.rotateLeft(value, 64));
+ assertEquals(value, BitRotate.rotateLeft(value, 96));
+ }
+
+ @Test
+ public void testRotateLeftShiftNormalization() {
+ // Test that shifts > 32 are properly normalized
+ int value = 1;
+ assertEquals(BitRotate.rotateLeft(value, 1), BitRotate.rotateLeft(value, 33));
+ assertEquals(BitRotate.rotateLeft(value, 5), BitRotate.rotateLeft(value, 37));
+ }
+
+ @Test
+ public void testRotateLeftZeroShift() {
+ // Zero shift should return original value
+ int value = 0xABCD1234;
+ assertEquals(value, BitRotate.rotateLeft(value, 0));
+ }
+
+ // ===== rotateRight Tests =====
+
+ @Test
+ public void testRotateRightBasic() {
+ // Basic right rotation
+ assertEquals(0b10000000_00000000_00000000_00000000, BitRotate.rotateRight(1, 1));
+ assertEquals(0b01000000_00000000_00000000_00000000, BitRotate.rotateRight(1, 2));
+ assertEquals(0b00100000_00000000_00000000_00000000, BitRotate.rotateRight(1, 3));
+ }
+
+ @Test
+ public void testRotateRightWithCarry() {
+ // Test bits carrying from right to left
+ // Binary: 00000000_00000000_00000000_00000011
+ int value = 3;
+ // After right rotate by 1: 10000000_00000000_00000000_00000001
+ assertEquals(0x80000001, BitRotate.rotateRight(value, 1));
+
+ // Binary: 00000000_00000000_00000000_00000001
+ value = 1;
+ // After right rotate by 1: 10000000_00000000_00000000_00000000
+ assertEquals(0x80000000, BitRotate.rotateRight(value, 1));
+ }
+
+ @Test
+ public void testRotateRightShift32() {
+ // Shift of 32 should be same as shift of 0 (modulo behavior)
+ int value = 0x9ABCDEF0;
+ assertEquals(value, BitRotate.rotateRight(value, 32));
+ assertEquals(value, BitRotate.rotateRight(value, 64));
+ assertEquals(value, BitRotate.rotateRight(value, 96));
+ }
+
+ @Test
+ public void testRotateRightShiftNormalization() {
+ // Test that shifts > 32 are properly normalized
+ int value = 1;
+ assertEquals(BitRotate.rotateRight(value, 1), BitRotate.rotateRight(value, 33));
+ assertEquals(BitRotate.rotateRight(value, 7), BitRotate.rotateRight(value, 39));
+ }
+
+ @Test
+ public void testRotateRightZeroShift() {
+ // Zero shift should return original value
+ int value = 0xDEADBEEF;
+ assertEquals(value, BitRotate.rotateRight(value, 0));
+ }
+
+ // ===== Edge Case Tests =====
+
+ @Test
+ public void testRotateLeftMaxValue() {
+ // Test with maximum integer value
+ int value = Integer.MAX_VALUE; // 0x7FFFFFFF
+ int rotated = BitRotate.rotateLeft(value, 1);
+ // MAX_VALUE << 1 should become 0xFFFFFFFE, but with rotation it becomes different
+ assertEquals(0xFFFFFFFE, rotated);
+ }
+
+ @Test
+ public void testRotateRightMinValue() {
+ // Test with minimum integer value (treated as unsigned)
+ int value = Integer.MIN_VALUE; // 0x80000000
+ int rotated = BitRotate.rotateRight(value, 1);
+ // MIN_VALUE >>> 1 should become 0x40000000, but with rotation from left
+ assertEquals(0x40000000, rotated);
+ }
+
+ @Test
+ public void testRotateAllOnes() {
+ // Test with all bits set
+ int value = 0xFFFFFFFF; // All ones
+ assertEquals(value, BitRotate.rotateLeft(value, 13));
+ assertEquals(value, BitRotate.rotateRight(value, 27));
+ }
+
+ @Test
+ public void testRotateAllZeros() {
+ // Test with all bits zero
+ int value = 0x00000000;
+ assertEquals(value, BitRotate.rotateLeft(value, 15));
+ assertEquals(value, BitRotate.rotateRight(value, 19));
+ }
+
+ // ===== Exception Tests =====
+
+ @Test
+ public void testRotateLeftNegativeShift() {
+ // Negative shifts should throw IllegalArgumentException
+ Exception exception = assertThrows(IllegalArgumentException.class, () -> BitRotate.rotateLeft(42, -1));
+ assertTrue(exception.getMessage().contains("negative"));
+ }
+
+ @Test
+ public void testRotateRightNegativeShift() {
+ // Negative shifts should throw IllegalArgumentException
+ Exception exception = assertThrows(IllegalArgumentException.class, () -> BitRotate.rotateRight(42, -5));
+ assertTrue(exception.getMessage().contains("negative"));
+ }
+
+ // ===== Complementary Operations Test =====
+
+ @Test
+ public void testRotateLeftRightComposition() {
+ // Rotating left then right by same amount should return original value
+ int original = 0x12345678;
+ int shift = 7;
+
+ int leftRotated = BitRotate.rotateLeft(original, shift);
+ int restored = BitRotate.rotateRight(leftRotated, shift);
+
+ assertEquals(original, restored);
+ }
+
+ @Test
+ public void testRotateRightLeftComposition() {
+ // Rotating right then left by same amount should return original value
+ int original = 0x9ABCDEF0;
+ int shift = 13;
+
+ int rightRotated = BitRotate.rotateRight(original, shift);
+ int restored = BitRotate.rotateLeft(rightRotated, shift);
+
+ assertEquals(original, restored);
+ }
+
+ @Test
+ public void testRotateLeft31IsSameAsRotateRight1() {
+ // Rotating left by 31 should be same as rotating right by 1
+ int value = 0x55555555;
+ assertEquals(BitRotate.rotateLeft(value, 31), BitRotate.rotateRight(value, 1));
+ }
+
+ @Test
+ public void testTraversals() {
+ // Test that methods don't throw exceptions
+ assertDoesNotThrow(() -> BitRotate.rotateLeft(1, 1));
+ assertDoesNotThrow(() -> BitRotate.rotateRight(1, 1));
+ }
+}
From 100462d8e97295a5867a8efd6301bf45b19d80b9 Mon Sep 17 00:00:00 2001
From: Sourav Pati
Date: Tue, 4 Nov 2025 02:59:44 +0530
Subject: [PATCH 126/272] Added LU Decomposition Algorithm for matrix (#6834)
* Added LU decomposition algorthm
* Added LU decomposition algorthim
* Added LU decomposition algorthim
* Added LU decomposition algorthim
* Added LU decomposition algorthim
* Added LU decomposition algorthim
* Added LU decomposition algorthim
* Added LU decomposition algorthim
* Added LU decomposition algorthim
---
.../thealgorithms/matrix/LUDecomposition.java | 88 +++++++++++++++++++
.../matrix/LUDecompositionTest.java | 40 +++++++++
2 files changed, 128 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/matrix/LUDecomposition.java
create mode 100644 src/test/java/com/thealgorithms/matrix/LUDecompositionTest.java
diff --git a/src/main/java/com/thealgorithms/matrix/LUDecomposition.java b/src/main/java/com/thealgorithms/matrix/LUDecomposition.java
new file mode 100644
index 000000000000..e41aaa201338
--- /dev/null
+++ b/src/main/java/com/thealgorithms/matrix/LUDecomposition.java
@@ -0,0 +1,88 @@
+package com.thealgorithms.matrix;
+
+/**
+ * LU Decomposition algorithm
+ * --------------------------
+ * Decomposes a square matrix a into a product of two matrices:
+ * a = l * u
+ * where:
+ * - l is a lower triangular matrix with 1s on its diagonal
+ * - u is an upper triangular matrix
+ *
+ * Reference:
+ * https://en.wikipedia.org/wiki/lu_decomposition
+ */
+public final class LUDecomposition {
+
+ private LUDecomposition() {
+ }
+
+ /**
+ * A helper class to store both l and u matrices
+ */
+ public static class LU {
+ double[][] l;
+ double[][] u;
+
+ LU(double[][] l, double[][] u) {
+ this.l = l;
+ this.u = u;
+ }
+ }
+
+ /**
+ * Performs LU Decomposition on a square matrix a
+ *
+ * @param a input square matrix
+ * @return LU object containing l and u matrices
+ */
+ public static LU decompose(double[][] a) {
+ int n = a.length;
+ double[][] l = new double[n][n];
+ double[][] u = new double[n][n];
+
+ for (int i = 0; i < n; i++) {
+ // upper triangular matrix
+ for (int k = i; k < n; k++) {
+ double sum = 0;
+ for (int j = 0; j < i; j++) {
+ sum += l[i][j] * u[j][k];
+ }
+ u[i][k] = a[i][k] - sum;
+ }
+
+ // lower triangular matrix
+ for (int k = i; k < n; k++) {
+ if (i == k) {
+ l[i][i] = 1; // diagonal as 1
+ } else {
+ double sum = 0;
+ for (int j = 0; j < i; j++) {
+ sum += l[k][j] * u[j][i];
+ }
+ l[k][i] = (a[k][i] - sum) / u[i][i];
+ }
+ }
+ }
+
+ return new LU(l, u);
+ }
+
+ /**
+ * Utility function to print a matrix
+ *
+ * @param m matrix to print
+ */
+ public static void printMatrix(double[][] m) {
+ for (double[] row : m) {
+ System.out.print("[");
+ for (int j = 0; j < row.length; j++) {
+ System.out.printf("%7.3f", row[j]);
+ if (j < row.length - 1) {
+ System.out.print(", ");
+ }
+ }
+ System.out.println("]");
+ }
+ }
+}
diff --git a/src/test/java/com/thealgorithms/matrix/LUDecompositionTest.java b/src/test/java/com/thealgorithms/matrix/LUDecompositionTest.java
new file mode 100644
index 000000000000..d3cc6d64bf42
--- /dev/null
+++ b/src/test/java/com/thealgorithms/matrix/LUDecompositionTest.java
@@ -0,0 +1,40 @@
+package com.thealgorithms.matrix;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class LUDecompositionTest {
+
+ @Test
+ public void testLUDecomposition() {
+ double[][] a = {{4, 3}, {6, 3}};
+
+ // Perform LU decomposition
+ LUDecomposition.LU lu = LUDecomposition.decompose(a);
+ double[][] l = lu.l;
+ double[][] u = lu.u;
+
+ // Reconstruct a from l and u
+ double[][] reconstructed = multiplyMatrices(l, u);
+
+ // Assert that reconstructed matrix matches original a
+ for (int i = 0; i < a.length; i++) {
+ assertArrayEquals(a[i], reconstructed[i], 1e-9);
+ }
+ }
+
+ // Helper method to multiply two matrices
+ private double[][] multiplyMatrices(double[][] a, double[][] b) {
+ int n = a.length;
+ double[][] c = new double[n][n];
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < n; j++) {
+ for (int k = 0; k < n; k++) {
+ c[i][j] += a[i][k] * b[k][j];
+ }
+ }
+ }
+ return c;
+ }
+}
From f0a437d08cfd8b8542d26793ad884b3af4e06206 Mon Sep 17 00:00:00 2001
From: Deniz Altunkapan
Date: Mon, 3 Nov 2025 23:26:10 +0100
Subject: [PATCH 127/272] Workflow/close failed prs (#6960)
* chore: add workflow to close stale PRs with failed workflows
* Include workflow failures when closing stale PRs
* Filter meaningful commits to only include those within the last 14 days
---
.github/workflows/close-failed-prs.yml | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/close-failed-prs.yml b/.github/workflows/close-failed-prs.yml
index f1bf3690f13f..6deea88f0daf 100644
--- a/.github/workflows/close-failed-prs.yml
+++ b/.github/workflows/close-failed-prs.yml
@@ -59,11 +59,13 @@ jobs:
const meaningfulCommits = commits.filter(c => {
const msg = c.commit.message.toLowerCase();
+ const date = new Date(c.commit.committer.date);
const isMergeFromMain = mainBranches.some(branch =>
msg.startsWith(`merge branch '${branch}'`) ||
msg.includes(`merge remote-tracking branch '${branch}'`)
);
- return !isMergeFromMain;
+
+ return !isMergeFromMain && date > cutoff;
});
// Get checks with error handling
@@ -151,4 +153,4 @@ jobs:
} catch (error) {
console.error(`❌ Fatal error: ${error.message}`);
throw error;
- }
\ No newline at end of file
+ }
From 5c965eb0977fbecb811e8f86d07a832bb75e3486 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 16:09:05 +0700
Subject: [PATCH 128/272] chore: fix typos in
src/test/java/com/thealgorithms/datastructures (#7045)
Fix typos in src/test/java/com/thealgorithms/datastructures
---
.../com/thealgorithms/datastructures/graphs/TwoSatTest.java | 2 +-
.../datastructures/lists/SinglyLinkedListTest.java | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/TwoSatTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/TwoSatTest.java
index 15e77b357f83..76b5aa8a780a 100644
--- a/src/test/java/com/thealgorithms/datastructures/graphs/TwoSatTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/TwoSatTest.java
@@ -8,7 +8,7 @@
/**
* Testcases for 2-SAT.
- * Please note thea whlie checking for boolean assignments always keep n + 1 elements and the first element should be always false.
+ * Please note thea while checking for boolean assignments always keep n + 1 elements and the first element should be always false.
*/
public class TwoSatTest {
private TwoSat twoSat;
diff --git a/src/test/java/com/thealgorithms/datastructures/lists/SinglyLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/SinglyLinkedListTest.java
index f80c6b5055f0..fde52b982385 100644
--- a/src/test/java/com/thealgorithms/datastructures/lists/SinglyLinkedListTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/lists/SinglyLinkedListTest.java
@@ -214,10 +214,10 @@ void recursiveReverseListTest() {
@Test
void readWithEnhancedForLoopTest() {
- final var expeced = new ArrayList(Arrays.asList(10, 20, 30));
+ final var expected = new ArrayList(Arrays.asList(10, 20, 30));
SinglyLinkedList list = new SinglyLinkedList();
- for (final var x : expeced) {
+ for (final var x : expected) {
list.insert(x);
}
@@ -226,7 +226,7 @@ void readWithEnhancedForLoopTest() {
readElements.add(x);
}
- assertEquals(readElements, expeced);
+ assertEquals(readElements, expected);
}
@Test
From 2ff284960aab62b5b8d307f074552881605f769f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 16:25:18 +0700
Subject: [PATCH 129/272] chore: fix typos in
src/main/java/com/thealgorithms/strings/Pangram.java (#7044)
Fix typos in src/main/java/com/thealgorithms/strings/Pangram.java
Co-authored-by: a 19151554+alxkm@users.noreply.github.com
---
src/main/java/com/thealgorithms/strings/Pangram.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/strings/Pangram.java b/src/main/java/com/thealgorithms/strings/Pangram.java
index 01307b28f6c6..a92c282d7e52 100644
--- a/src/main/java/com/thealgorithms/strings/Pangram.java
+++ b/src/main/java/com/thealgorithms/strings/Pangram.java
@@ -60,7 +60,7 @@ public static boolean isPangram(String s) {
}
/**
- * Checks if a String is Pangram or not by checking if each alhpabet is present or not
+ * Checks if a String is Pangram or not by checking if each alphabet is present or not
*
* @param s The String to check
* @return {@code true} if s is a Pangram, otherwise {@code false}
From c42e73bd95cacc76de971aabaf37fce94d3105d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 16:36:52 +0700
Subject: [PATCH 130/272] chore: fix typos in
src/main/java/com/thealgorithms/others/MemoryManagementAlgorithms.java
(#7043)
Fix typos in src/main/java/com/thealgorithms/others/MemoryManagementAlgorithms.java
Co-authored-by: a <19151554+alxkm@users.noreply.github.com>
---
.../others/MemoryManagementAlgorithms.java | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/main/java/com/thealgorithms/others/MemoryManagementAlgorithms.java b/src/main/java/com/thealgorithms/others/MemoryManagementAlgorithms.java
index 0924b8569942..40a5f6a7a767 100644
--- a/src/main/java/com/thealgorithms/others/MemoryManagementAlgorithms.java
+++ b/src/main/java/com/thealgorithms/others/MemoryManagementAlgorithms.java
@@ -16,7 +16,7 @@ public abstract class MemoryManagementAlgorithms {
* blocks available.
* @param sizeOfProcesses: an int array that contains the sizes of the
* processes we need memory blocks for.
- * @return the ArrayList filled with Integers repressenting the memory
+ * @return the ArrayList filled with Integers representing the memory
* allocation that took place.
*/
public abstract ArrayList fitProcess(int[] sizeOfBlocks, int[] sizeOfProcesses);
@@ -91,7 +91,7 @@ private static int findBestFit(int[] blockSizes, int processSize) {
* blocks available.
* @param sizeOfProcesses: an int array that contains the sizes of the
* processes we need memory blocks for.
- * @return the ArrayList filled with Integers repressenting the memory
+ * @return the ArrayList filled with Integers representing the memory
* allocation that took place.
*/
public ArrayList fitProcess(int[] sizeOfBlocks, int[] sizeOfProcesses) {
@@ -149,7 +149,7 @@ private static int findWorstFit(int[] blockSizes, int processSize) {
* blocks available.
* @param sizeOfProcesses: an int array that contains the sizes of the
* processes we need memory blocks for.
- * @return the ArrayList filled with Integers repressenting the memory
+ * @return the ArrayList filled with Integers representing the memory
* allocation that took place.
*/
public ArrayList fitProcess(int[] sizeOfBlocks, int[] sizeOfProcesses) {
@@ -201,7 +201,7 @@ private static int findFirstFit(int[] blockSizes, int processSize) {
* blocks available.
* @param sizeOfProcesses: an int array that contains the sizes of the
* processes we need memory blocks for.
- * @return the ArrayList filled with Integers repressenting the memory
+ * @return the ArrayList filled with Integers representing the memory
* allocation that took place.
*/
public ArrayList fitProcess(int[] sizeOfBlocks, int[] sizeOfProcesses) {
@@ -262,7 +262,7 @@ private int findNextFit(int[] blockSizes, int processSize) {
* blocks available.
* @param sizeOfProcesses: an int array that contains the sizes of the
* processes we need memory blocks for.
- * @return the ArrayList filled with Integers repressenting the memory
+ * @return the ArrayList filled with Integers representing the memory
* allocation that took place.
*/
public ArrayList fitProcess(int[] sizeOfBlocks, int[] sizeOfProcesses) {
From a3717f0563e819c85d369d502ff03a0769d37593 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 16:43:02 +0700
Subject: [PATCH 131/272] chore: fix typos in
src/main/java/com/thealgorithms/others/IterativeFloodFill.java (#7042)
Fix typos in src/main/java/com/thealgorithms/others/IterativeFloodFill.java
---
.../java/com/thealgorithms/others/IterativeFloodFill.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/main/java/com/thealgorithms/others/IterativeFloodFill.java b/src/main/java/com/thealgorithms/others/IterativeFloodFill.java
index 3ef90369bd52..3f685f418a3d 100644
--- a/src/main/java/com/thealgorithms/others/IterativeFloodFill.java
+++ b/src/main/java/com/thealgorithms/others/IterativeFloodFill.java
@@ -32,8 +32,8 @@ private IterativeFloodFill() {
* Iteratively fill the 2D image with new color
*
* @param image The image to be filled
- * @param x The x co-ordinate at which color is to be filled
- * @param y The y co-ordinate at which color is to be filled
+ * @param x The x coordinate at which color is to be filled
+ * @param y The y coordinate at which color is to be filled
* @param newColor The new color which to be filled in the image
* @param oldColor The old color which is to be replaced in the image
* @see FloodFill BFS
@@ -86,8 +86,8 @@ private static class Point {
* Checks if a pixel should be skipped during flood fill operation.
*
* @param image The image to get boundaries
- * @param x The x co-ordinate of pixel to check
- * @param y The y co-ordinate of pixel to check
+ * @param x The x coordinate of pixel to check
+ * @param y The y coordinate of pixel to check
* @param oldColor The old color which is to be replaced in the image
* @return {@code true} if pixel should be skipped, else {@code false}
*/
From 08ee26f2b8bbff2f71086b7ddb57a9000783c289 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 16:50:43 +0700
Subject: [PATCH 132/272] chore: fix typos in
src/main/java/com/thealgorithms/others/Implementing_auto_completing_features_using_trie.java
(#7041)
Fix typos in src/main/java/com/thealgorithms/others/Implementing_auto_completing_features_using_trie.java
---
.../Implementing_auto_completing_features_using_trie.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/others/Implementing_auto_completing_features_using_trie.java b/src/main/java/com/thealgorithms/others/Implementing_auto_completing_features_using_trie.java
index bb88c7e3ae2f..7a1a7aadd805 100644
--- a/src/main/java/com/thealgorithms/others/Implementing_auto_completing_features_using_trie.java
+++ b/src/main/java/com/thealgorithms/others/Implementing_auto_completing_features_using_trie.java
@@ -97,7 +97,7 @@ static void suggestionsRec(TrieNode root, String currPrefix) {
}
}
- // Fucntion to print suggestions for
+ // Function to print suggestions for
// given query prefix.
static int printAutoSuggestions(TrieNode root, final String query) {
TrieNode pCrawl = root;
From d92ab9d89ca296a700cb56909b987f61e03ff484 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 16:56:34 +0700
Subject: [PATCH 133/272] chore: fix typos in
src/main/java/com/thealgorithms/others/GaussLegendre.java (#7040)
Fix typos in src/main/java/com/thealgorithms/others/GaussLegendre.java
---
src/main/java/com/thealgorithms/others/GaussLegendre.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/others/GaussLegendre.java b/src/main/java/com/thealgorithms/others/GaussLegendre.java
index b56b51f158fb..acf76ae3b192 100644
--- a/src/main/java/com/thealgorithms/others/GaussLegendre.java
+++ b/src/main/java/com/thealgorithms/others/GaussLegendre.java
@@ -1,7 +1,7 @@
package com.thealgorithms.others;
/**
- * Guass Legendre Algorithm ref
+ * Gauss Legendre Algorithm ref
* https://en.wikipedia.org/wiki/Gauss–Legendre_algorithm
*
* @author AKS1996
From 26b47cb5b80c0faa9ead2460f2548b8cb32201dd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 17:02:56 +0700
Subject: [PATCH 134/272] chore: fix typos in
src/main/java/com/thealgorithms/others/BankersAlgorithm.java (#7039)
Fix typos in src/main/java/com/thealgorithms/others/BankersAlgorithm.java
---
src/main/java/com/thealgorithms/others/BankersAlgorithm.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/others/BankersAlgorithm.java b/src/main/java/com/thealgorithms/others/BankersAlgorithm.java
index 836526529374..5abf633a1c12 100644
--- a/src/main/java/com/thealgorithms/others/BankersAlgorithm.java
+++ b/src/main/java/com/thealgorithms/others/BankersAlgorithm.java
@@ -3,7 +3,7 @@
import java.util.Scanner;
/**
- * This file contains an implementation of BANKER'S ALGORITM Wikipedia:
+ * This file contains an implementation of BANKER'S ALGORITHM Wikipedia:
* https://en.wikipedia.org/wiki/Banker%27s_algorithm
*
* The algorithm for finding out whether or not a system is in a safe state can
From 3b14d6d3987e4f52c73c3372cedc89ddae9ed895 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 17:13:26 +0700
Subject: [PATCH 135/272] chore: fix typos in
src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java (#7038)
Fix typos in src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java
---
.../java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java b/src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java
index 9a7f255282ac..7ee8a1a9f0ed 100644
--- a/src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java
+++ b/src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java
@@ -40,7 +40,7 @@ static void printMatrix(int[][] arr) {
}
/**
- * Class containing the algo to roate matrix by 90 degree
+ * Class containing the algo to rotate matrix by 90 degree
*/
final class Rotate {
private Rotate() {
From 1645f31e790b6c3ae36ddae81b654e6e5fbc0960 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 17:16:55 +0700
Subject: [PATCH 136/272] chore: fix typos in
src/main/java/com/thealgorithms/maths/SieveOfAtkin.java (#7037)
Fix typos in src/main/java/com/thealgorithms/maths/SieveOfAtkin.java
Co-authored-by: a <19151554+alxkm@users.noreply.github.com>
---
src/main/java/com/thealgorithms/maths/SieveOfAtkin.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java b/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java
index ee59d0784ec4..780dd81dac7c 100644
--- a/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java
+++ b/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java
@@ -14,7 +14,7 @@
public final class SieveOfAtkin {
private SieveOfAtkin() {
- // Utlity class; prevent instantiation
+ // Utility class; prevent instantiation
}
/**
From f403ce66f9894b7c15e786dc468eb52ac2ade5f4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 17:23:30 +0700
Subject: [PATCH 137/272] chore: fix typos in
src/main/java/com/thealgorithms/maths/BinomialCoefficient.java (#7036)
Fix typos in src/main/java/com/thealgorithms/maths/BinomialCoefficient.java
Co-authored-by: a <19151554+alxkm@users.noreply.github.com>
---
.../java/com/thealgorithms/maths/BinomialCoefficient.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/com/thealgorithms/maths/BinomialCoefficient.java b/src/main/java/com/thealgorithms/maths/BinomialCoefficient.java
index faec049b08a7..1de39adbc18a 100644
--- a/src/main/java/com/thealgorithms/maths/BinomialCoefficient.java
+++ b/src/main/java/com/thealgorithms/maths/BinomialCoefficient.java
@@ -1,8 +1,8 @@
package com.thealgorithms.maths;
/*
- * Java program for Binomial Cofficients
- * Binomial Cofficients: A binomial cofficient C(n,k) gives number ways
+ * Java program for Binomial Coefficients
+ * Binomial Coefficients: A binomial coefficient C(n,k) gives number ways
* in which k objects can be chosen from n objects.
* Wikipedia: https://en.wikipedia.org/wiki/Binomial_coefficient
*
From 500c5264519a389e57e8c094c876e414cb49be7f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 17:27:10 +0700
Subject: [PATCH 138/272] chore: fix typos in
src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java
(#7035)
Fix typos in src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java
---
.../com/thealgorithms/divideandconquer/SkylineAlgorithm.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java b/src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java
index 610b1b78a36a..0e8d9442138c 100644
--- a/src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java
+++ b/src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java
@@ -161,7 +161,7 @@ public int getY() {
* function dominates the argument point.
*
* @param p1 the point that is compared
- * @return true if the point wich calls the function dominates p1 false
+ * @return true if the point which calls the function dominates p1 false
* otherwise.
*/
public boolean dominates(Point p1) {
From 88c8e3935cf21dc97afc0298b519b0f19db3eeec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 17:31:34 +0700
Subject: [PATCH 139/272] chore: fix typos in
src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java (#7034)
Fix typos in src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java
Co-authored-by: a <19151554+alxkm@users.noreply.github.com>
---
.../java/com/thealgorithms/divideandconquer/ClosestPair.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java b/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java
index cd26f9213651..4c9c40c83174 100644
--- a/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java
+++ b/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java
@@ -182,7 +182,7 @@ public double closestPair(final Location[] a, final int indexNum) {
double minLeftArea; // Minimum length of left array
double minRightArea; // Minimum length of right array
- double minValue; // Minimum lengt
+ double minValue; // Minimum length
minLeftArea = closestPair(leftArray, divideX); // recursive closestPair
minRightArea = closestPair(rightArray, indexNum - divideX);
From b87b1102d0f12219dc288707d6141b283839d676 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 17:35:18 +0700
Subject: [PATCH 140/272] chore: fix typos in
src/main/java/com/thealgorithms/datastructures/queues/PriorityQueues.java
(#7028)
Fix typos in src/main/java/com/thealgorithms/datastructures/queues/PriorityQueues.java
Co-authored-by: a <19151554+alxkm@users.noreply.github.com>
---
.../datastructures/queues/PriorityQueues.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/main/java/com/thealgorithms/datastructures/queues/PriorityQueues.java b/src/main/java/com/thealgorithms/datastructures/queues/PriorityQueues.java
index a5ca48670f2c..b877a5843b98 100644
--- a/src/main/java/com/thealgorithms/datastructures/queues/PriorityQueues.java
+++ b/src/main/java/com/thealgorithms/datastructures/queues/PriorityQueues.java
@@ -9,7 +9,7 @@
* give numbers that are bigger, a higher priority. Queues in theory have no
* fixed size but when using an array implementation it does.
*
- * Additional contibutions made by: PuneetTri(https://github.com/PuneetTri)
+ * Additional contributions made by: PuneetTri(https://github.com/PuneetTri)
*/
class PriorityQueue {
@@ -32,8 +32,8 @@ class PriorityQueue {
PriorityQueue() {
/* If capacity is not defined, default size of 11 would be used
- * capacity=max+1 because we cant access 0th element of PQ, and to
- * accomodate (max)th elements we need capacity to be max+1.
+ * capacity=max+1 because we can't access 0th element of PQ, and to
+ * accommodate (max)th elements we need capacity to be max+1.
* Parent is at position k, child at position (k*2,k*2+1), if we
* use position 0 in our queue, its child would be at:
* (0*2, 0*2+1) -> (0,0). This is why we start at position 1
@@ -127,7 +127,7 @@ public int remove() {
if (isEmpty()) {
throw new RuntimeException("Queue is Empty");
} else {
- int max = queueArray[1]; // By defintion of our max-heap, value at queueArray[1] pos is
+ int max = queueArray[1]; // By definition of our max-heap, value at queueArray[1] pos is
// the greatest
// Swap max and last element
From 19f0f0bd83fb350004f375df180d3f65089013d8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 17:40:08 +0700
Subject: [PATCH 141/272] chore: fix typos in
src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java
(#7024)
Fix typos in src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java
---
.../com/thealgorithms/conversions/TurkishToLatinConversion.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java b/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java
index 30030de6c1bd..50726380621a 100644
--- a/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java
+++ b/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java
@@ -16,7 +16,7 @@ private TurkishToLatinConversion() {
* 2. Replace all turkish characters with their corresponding latin characters
* 3. Return the converted string
*
- * @param param String paramter
+ * @param param String parameter
* @return String
*/
public static String convertTurkishToLatin(String param) {
From dd01b35d973a7021b3d8a6a56cf9b21f61c49016 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 17:44:45 +0700
Subject: [PATCH 142/272] chore: fix typos in
src/main/java/com/thealgorithms/datastructures/graphs/BellmanFord.java
(#7025)
Fix typos in src/main/java/com/thealgorithms/datastructures/graphs/BellmanFord.java
Co-authored-by: a <19151554+alxkm@users.noreply.github.com>
---
.../com/thealgorithms/datastructures/graphs/BellmanFord.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/BellmanFord.java b/src/main/java/com/thealgorithms/datastructures/graphs/BellmanFord.java
index 47c5f0d0b98e..5184dae58d28 100644
--- a/src/main/java/com/thealgorithms/datastructures/graphs/BellmanFord.java
+++ b/src/main/java/com/thealgorithms/datastructures/graphs/BellmanFord.java
@@ -160,7 +160,7 @@ public void show(int source, int end,
break;
}
}
- if (neg == 0) { // Go ahead and show results of computaion
+ if (neg == 0) { // Go ahead and show results of computation
System.out.println("Distance is: " + dist[end]);
System.out.println("Path followed:");
System.out.print(source + " ");
From fab09e7da17325a99ef9033d585f978e26867435 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 17:48:33 +0700
Subject: [PATCH 143/272] chore: fix typos in
src/main/java/com/thealgorithms/datastructures/graphs/MatrixGraphs.java
(#7026)
Fix typos in src/main/java/com/thealgorithms/datastructures/graphs/MatrixGraphs.java
Co-authored-by: a <19151554+alxkm@users.noreply.github.com>
---
.../com/thealgorithms/datastructures/graphs/MatrixGraphs.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/MatrixGraphs.java b/src/main/java/com/thealgorithms/datastructures/graphs/MatrixGraphs.java
index c1d47df457da..a54b0b75e4dc 100644
--- a/src/main/java/com/thealgorithms/datastructures/graphs/MatrixGraphs.java
+++ b/src/main/java/com/thealgorithms/datastructures/graphs/MatrixGraphs.java
@@ -141,7 +141,7 @@ private int[][] adjacency() {
*
* @param from the parent vertex to check for adjacency
* @param to the child vertex to check for adjacency
- * @return whether or not the vertices are adjancent
+ * @return whether or not the vertices are adjacent
*/
private boolean adjacencyOfEdgeDoesExist(int from, int to) {
return (this.adjacency()[from][to] != AdjacencyMatrixGraph.EDGE_NONE);
@@ -162,7 +162,7 @@ public boolean vertexDoesExist(int aVertex) {
*
* @param from the parent vertex to check for adjacency
* @param to the child vertex to check for adjacency
- * @return whether or not the vertices are adjancent
+ * @return whether or not the vertices are adjacent
*/
public boolean edgeDoesExist(int from, int to) {
if (this.vertexDoesExist(from) && this.vertexDoesExist(to)) {
From 8ae57476b1298601c37da6742bb85902f2ac9b95 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 17:53:11 +0700
Subject: [PATCH 144/272] chore: fix typos in
src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java (#7033)
Fix typos in src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java
---
src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java b/src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java
index 13c9212306c1..1639bec6e5a0 100644
--- a/src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java
+++ b/src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java
@@ -12,7 +12,7 @@
public abstract class TreeNode extends Node {
/**
- * Refernce to the parent Node.
+ * Reference to the parent Node.
*/
private TreeNode parentNode;
/**
@@ -21,7 +21,7 @@ public abstract class TreeNode extends Node {
private int depth;
/**
- * Empty contructor.
+ * Empty constructor.
*/
public TreeNode() {
super();
From 96304bda3008db17c2dab589c6415f25eb7aba06 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 17:56:44 +0700
Subject: [PATCH 145/272] chore: fix typos in
src/main/java/com/thealgorithms/devutils/nodes/SimpleTreeNode.java (#7032)
Fix typos in src/main/java/com/thealgorithms/devutils/nodes/SimpleTreeNode.java
---
.../com/thealgorithms/devutils/nodes/SimpleTreeNode.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/main/java/com/thealgorithms/devutils/nodes/SimpleTreeNode.java b/src/main/java/com/thealgorithms/devutils/nodes/SimpleTreeNode.java
index 215f01a6ef59..eefffacee8d6 100644
--- a/src/main/java/com/thealgorithms/devutils/nodes/SimpleTreeNode.java
+++ b/src/main/java/com/thealgorithms/devutils/nodes/SimpleTreeNode.java
@@ -11,16 +11,16 @@
public class SimpleTreeNode extends TreeNode {
/**
- * Refrence to the child Node on the left.
+ * Reference to the child Node on the left.
*/
private SimpleTreeNode leftNode;
/**
- * Refrence to the child Node on the right.
+ * Reference to the child Node on the right.
*/
private SimpleTreeNode rightNode;
/**
- * Empty contructor.
+ * Empty constructor.
*/
public SimpleTreeNode() {
super();
From 65eeb5579e9a7c41a5037502b7d239e71e848ca4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 18:01:44 +0700
Subject: [PATCH 146/272] chore: fix typos in
src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java (#7031)
Fix typos in src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java
Co-authored-by: a <19151554+alxkm@users.noreply.github.com>
---
src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java b/src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java
index 769ffc2a9a96..bf3e795dd74b 100644
--- a/src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java
+++ b/src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java
@@ -15,7 +15,7 @@ public class SimpleNode extends Node {
private SimpleNode nextNode;
/**
- * Empty contructor.
+ * Empty constructor.
*/
public SimpleNode() {
super();
From d75a66887033913b798be4a720f2b2b998f4f078 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 18:05:13 +0700
Subject: [PATCH 147/272] chore: fix typos in
src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java
(#7030)
Fix typos in src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java
---
.../thealgorithms/datastructures/trees/BSTRecursiveGeneric.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java b/src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java
index 0245372fe012..2c94224ddeb4 100644
--- a/src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java
+++ b/src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java
@@ -30,7 +30,7 @@ public BSTRecursiveGeneric() {
}
/**
- * Displays the tree is a structed format
+ * Displays the tree is a structured format
*/
public void prettyDisplay() {
prettyDisplay(root, 0);
From 0c277a1d9e1be23df1a0063ed5524f9640c15258 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 18:08:49 +0700
Subject: [PATCH 148/272] chore: fix typos in
src/main/java/com/thealgorithms/datastructures/heaps/FibonacciHeap.java
(#7027)
Fix typos in src/main/java/com/thealgorithms/datastructures/heaps/FibonacciHeap.java
---
.../com/thealgorithms/datastructures/heaps/FibonacciHeap.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/datastructures/heaps/FibonacciHeap.java b/src/main/java/com/thealgorithms/datastructures/heaps/FibonacciHeap.java
index 7a263fc08ac5..834de9c77881 100644
--- a/src/main/java/com/thealgorithms/datastructures/heaps/FibonacciHeap.java
+++ b/src/main/java/com/thealgorithms/datastructures/heaps/FibonacciHeap.java
@@ -387,7 +387,7 @@ public class HeapNode {
private HeapNode parent;
/*
- * a constructor for a heapNode withe key @param (key)
+ * a constructor for a heapNode with key @param (key)
* prev == next == this
* parent == child == null
*/
From 8c8527c2c8a8b68033937b565029bc36e15f1b7a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 18:12:14 +0700
Subject: [PATCH 149/272] chore: fix typos in
src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java (#7029)
Fix typos in src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java
---
.../java/com/thealgorithms/datastructures/trees/AVLSimple.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java b/src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java
index e0309122cc12..07fc5c87b6c4 100644
--- a/src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java
+++ b/src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java
@@ -1,7 +1,7 @@
package com.thealgorithms.datastructures.trees;
/*
-* Avl is algo that balance itself while adding new alues to tree
+* Avl is algo that balance itself while adding new values to tree
* by rotating branches of binary tree and make itself Binary seaarch tree
* there are four cases which has to tackle
* rotating - left right ,left left,right right,right left
From 53230842f2e8bdff9cc7363b876a45a2de151bf6 Mon Sep 17 00:00:00 2001
From: Avaneeshakrishna <36323856+Avaneeshakrishna@users.noreply.github.com>
Date: Wed, 5 Nov 2025 03:22:39 -0800
Subject: [PATCH 150/272] add CombinationSum and test (#6725)
* add CombinationSum and test
* Format array and list literals in CombinationSumTest
* Fix sorting comparator in CombinationSumTest
* Refactor CombinationSum for better handling and clarity
Updated combinationSum method to handle null or empty candidates and improved variable naming for clarity.
* Fix sorting comparator in CombinationSumTest
* Update CombinationSumTest.java
* Fix sorting comparator for list of integers
* Fix formatting issues in CombinationSum class
* Change CombinationSum class to final
* Refactor norm method to accept Iterable instead of List
* Remove unnecessary whitespace in CombinationSumTest
---
.../backtracking/CombinationSum.java | 48 +++++++++++++++++++
.../backtracking/CombinationSumTest.java | 29 +++++++++++
2 files changed, 77 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/backtracking/CombinationSum.java
create mode 100644 src/test/java/com/thealgorithms/backtracking/CombinationSumTest.java
diff --git a/src/main/java/com/thealgorithms/backtracking/CombinationSum.java b/src/main/java/com/thealgorithms/backtracking/CombinationSum.java
new file mode 100644
index 000000000000..09b99032bdc1
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/CombinationSum.java
@@ -0,0 +1,48 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/** Backtracking: pick/not-pick with reuse of candidates. */
+public final class CombinationSum {
+ private CombinationSum() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ public static List> combinationSum(int[] candidates, int target) {
+ List> results = new ArrayList<>();
+ if (candidates == null || candidates.length == 0) {
+ return results;
+ }
+
+ // Sort to help with pruning duplicates and early termination
+ Arrays.sort(candidates);
+ backtrack(candidates, target, 0, new ArrayList<>(), results);
+ return results;
+ }
+
+ private static void backtrack(int[] candidates, int remaining, int start, List combination, List> results) {
+ if (remaining == 0) {
+ // Found valid combination; add a copy
+ results.add(new ArrayList<>(combination));
+ return;
+ }
+
+ for (int i = start; i < candidates.length; i++) {
+ int candidate = candidates[i];
+
+ // If candidate is greater than remaining target, further candidates (sorted) will also be too big
+ if (candidate > remaining) {
+ break;
+ }
+
+ // include candidate
+ combination.add(candidate);
+ // Because we can reuse the same element, we pass i (not i + 1)
+ backtrack(candidates, remaining - candidate, i, combination, results);
+ // backtrack: remove last
+ combination.remove(combination.size() - 1);
+ }
+ }
+}
diff --git a/src/test/java/com/thealgorithms/backtracking/CombinationSumTest.java b/src/test/java/com/thealgorithms/backtracking/CombinationSumTest.java
new file mode 100644
index 000000000000..986c71acebe8
--- /dev/null
+++ b/src/test/java/com/thealgorithms/backtracking/CombinationSumTest.java
@@ -0,0 +1,29 @@
+package com.thealgorithms.backtracking;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+class CombinationSumTest {
+ private static List> norm(Iterable> x) {
+ List> y = new ArrayList<>();
+ for (var p : x) {
+ var q = new ArrayList<>(p);
+ q.sort(Integer::compare);
+ y.add(q);
+ }
+ y.sort(Comparator.>comparingInt(List::size).thenComparing(Object::toString));
+ return y;
+ }
+
+ @Test
+ void sample() {
+ int[] candidates = {2, 3, 6, 7};
+ int target = 7;
+ var expected = List.of(List.of(2, 2, 3), List.of(7));
+ assertEquals(norm(expected), norm(CombinationSum.combinationSum(candidates, target)));
+ }
+}
From 702664116d73dd8283c307bec606b6a31bdb70c6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 22:41:33 +0700
Subject: [PATCH 151/272] chore: fix typos in
src/main/java/com/thealgorithms/backtracking/FloodFill.java (#7046)
Fix typos in src/main/java/com/thealgorithms/backtracking/FloodFill.java
---
.../com/thealgorithms/backtracking/FloodFill.java | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/main/java/com/thealgorithms/backtracking/FloodFill.java b/src/main/java/com/thealgorithms/backtracking/FloodFill.java
index c8219ca8ba7e..0f31a9c5a30e 100644
--- a/src/main/java/com/thealgorithms/backtracking/FloodFill.java
+++ b/src/main/java/com/thealgorithms/backtracking/FloodFill.java
@@ -12,8 +12,8 @@ private FloodFill() {
* Get the color at the given coordinates of a 2D image
*
* @param image The image to be filled
- * @param x The x co-ordinate of which color is to be obtained
- * @param y The y co-ordinate of which color is to be obtained
+ * @param x The x coordinate of which color is to be obtained
+ * @param y The y coordinate of which color is to be obtained
*/
public static int getPixel(final int[][] image, final int x, final int y) {
@@ -24,8 +24,8 @@ public static int getPixel(final int[][] image, final int x, final int y) {
* Put the color at the given coordinates of a 2D image
*
* @param image The image to be filled
- * @param x The x co-ordinate at which color is to be filled
- * @param y The y co-ordinate at which color is to be filled
+ * @param x The x coordinate at which color is to be filled
+ * @param y The y coordinate at which color is to be filled
*/
public static void putPixel(final int[][] image, final int x, final int y, final int newColor) {
image[x][y] = newColor;
@@ -35,8 +35,8 @@ public static void putPixel(final int[][] image, final int x, final int y, final
* Fill the 2D image with new color
*
* @param image The image to be filled
- * @param x The x co-ordinate at which color is to be filled
- * @param y The y co-ordinate at which color is to be filled
+ * @param x The x coordinate at which color is to be filled
+ * @param y The y coordinate at which color is to be filled
* @param newColor The new color which to be filled in the image
* @param oldColor The old color which is to be replaced in the image
*/
From 147da38888303b195c8d95a6f86dacfec9c5f665 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 22:45:27 +0700
Subject: [PATCH 152/272] chore: fix typos in
src/main/java/com/thealgorithms/ciphers/AES.java (#7047)
Fix typos in src/main/java/com/thealgorithms/ciphers/AES.java
Co-authored-by: Deniz Altunkapan
---
src/main/java/com/thealgorithms/ciphers/AES.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/ciphers/AES.java b/src/main/java/com/thealgorithms/ciphers/AES.java
index 1c283f6b7655..df51eba55310 100644
--- a/src/main/java/com/thealgorithms/ciphers/AES.java
+++ b/src/main/java/com/thealgorithms/ciphers/AES.java
@@ -2738,7 +2738,7 @@ public static BigInteger decrypt(BigInteger cipherText, BigInteger key) {
public static void main(String[] args) {
try (Scanner input = new Scanner(System.in)) {
- System.out.println("Enter (e) letter for encrpyt or (d) letter for decrypt :");
+ System.out.println("Enter (e) letter for encrypt or (d) letter for decrypt :");
char choice = input.nextLine().charAt(0);
String in;
switch (choice) {
From c7cb54ed84f98e0d130caf3b4335c9eed69101d3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 22:49:00 +0700
Subject: [PATCH 153/272] chore: fix typos in
src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.java
(#7048)
Fix typos in src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.java
---
.../datastructures/trees/CeilInBinarySearchTree.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.java b/src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.java
index 214e111b9f1a..fff84111663b 100644
--- a/src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.java
+++ b/src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.java
@@ -21,7 +21,7 @@
*
* Solution 1: Brute Force Solution: Do an inorder traversal and save result
* into an array. Iterate over the array to get an element equal to or greater
- * than current key. Time Complexity: O(n) Space Complexity: O(n) for auxillary
+ * than current key. Time Complexity: O(n) Space Complexity: O(n) for auxiliary
* array to save inorder representation of tree.
*
*
@@ -29,7 +29,7 @@
* into an array.Since array is sorted do a binary search over the array to get
* an element equal to or greater than current key. Time Complexity: O(n) for
* traversal of tree and O(lg(n)) for binary search in array. Total = O(n) Space
- * Complexity: O(n) for auxillary array to save inorder representation of tree.
+ * Complexity: O(n) for auxiliary array to save inorder representation of tree.
*
*
* Solution 3: Optimal We can do a DFS search on given tree in following
From d28fee96650f9a295708d813b2c135081bbfc6b8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Wed, 5 Nov 2025 22:53:18 +0700
Subject: [PATCH 154/272] chore: fix typos in
src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java (#7049)
Fix typos in src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java
---
.../dynamicprogramming/BoundaryFill.java | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java b/src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java
index 8494492f293f..ccd54ee4349a 100644
--- a/src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java
@@ -12,8 +12,8 @@ private BoundaryFill() {
* Get the color at the given co-odrinates of a 2D image
*
* @param image The image to be filled
- * @param xCoordinate The x co-ordinate of which color is to be obtained
- * @param yCoordinate The y co-ordinate of which color is to be obtained
+ * @param xCoordinate The x coordinate of which color is to be obtained
+ * @param yCoordinate The y coordinate of which color is to be obtained
*/
public static int getPixel(int[][] image, int xCoordinate, int yCoordinate) {
return image[xCoordinate][yCoordinate];
@@ -23,8 +23,8 @@ public static int getPixel(int[][] image, int xCoordinate, int yCoordinate) {
* Put the color at the given co-odrinates of a 2D image
*
* @param image The image to be filed
- * @param xCoordinate The x co-ordinate at which color is to be filled
- * @param yCoordinate The y co-ordinate at which color is to be filled
+ * @param xCoordinate The x coordinate at which color is to be filled
+ * @param yCoordinate The y coordinate at which color is to be filled
*/
public static void putPixel(int[][] image, int xCoordinate, int yCoordinate, int newColor) {
image[xCoordinate][yCoordinate] = newColor;
@@ -34,8 +34,8 @@ public static void putPixel(int[][] image, int xCoordinate, int yCoordinate, int
* Fill the 2D image with new color
*
* @param image The image to be filed
- * @param xCoordinate The x co-ordinate at which color is to be filled
- * @param yCoordinate The y co-ordinate at which color is to be filled
+ * @param xCoordinate The x coordinate at which color is to be filled
+ * @param yCoordinate The y coordinate at which color is to be filled
* @param newColor The new color which to be filled in the image
* @param boundaryColor The old color which is to be replaced in the image
*/
From d126fd59f7c4f9aac8de23db2766bc6f6121394d Mon Sep 17 00:00:00 2001
From: Arzoo1701 <122432635+Arzoo1701@users.noreply.github.com>
Date: Wed, 5 Nov 2025 23:11:08 +0530
Subject: [PATCH 155/272] Add Trapping Rainwater problem implementation (Two
Pointer Approach) (#6990)
* Add Trapping Rainwater problem implementation (Two Pointer Approach)
* Add Wikipedia reference link for Trapping Rainwater problem
* fix: format TrappingRainwater.java for CI check
* fix: add package and resolve checkstyle errors for TrappingRainwater.java
* fix: declare TrappingRainwater as final to pass Checkstyle
* Add test cases for TrappingRainwater algorithm
* Add test cases for TrappingRainwater algorithm
* Move TrappingRainwater algorithm to stacks package
* Fix: Move TrappingRainwater to stacks and normalize newline in JugglerSequence
* Fix: Normalize newline in JugglerSequence to ensure test consistency
* Fix: Normalize newline in JugglerSequence and remove return statement
* Add JaCoCo plugin for code coverage reporting
* Revert pom.xml to original version from master
* Fix: Revert the pom.xml file
---------
Co-authored-by: Deniz Altunkapan
---
pom.xml | 2 +-
.../stacks/TrappingRainwater.java | 48 +++++++++++++++++++
.../stacks/TrappingRainwaterTest.java | 38 +++++++++++++++
3 files changed, 87 insertions(+), 1 deletion(-)
create mode 100644 src/main/java/com/thealgorithms/stacks/TrappingRainwater.java
create mode 100644 src/test/java/com/thealgorithms/stacks/TrappingRainwaterTest.java
diff --git a/pom.xml b/pom.xml
index 825d86f8b239..7e936967208b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -155,4 +155,4 @@
-
+
\ No newline at end of file
diff --git a/src/main/java/com/thealgorithms/stacks/TrappingRainwater.java b/src/main/java/com/thealgorithms/stacks/TrappingRainwater.java
new file mode 100644
index 000000000000..072665061b8e
--- /dev/null
+++ b/src/main/java/com/thealgorithms/stacks/TrappingRainwater.java
@@ -0,0 +1,48 @@
+package com.thealgorithms.stacks;
+/**
+ * Trapping Rainwater Problem
+ * Given an array of non-negative integers representing the height of bars,
+ * compute how much water it can trap after raining.
+ *
+ * Example:
+ * Input: [4,2,0,3,2,5]
+ * Output: 9
+ *
+ * Time Complexity: O(n)
+ * Space Complexity: O(1)
+ *
+ * Reference: https://en.wikipedia.org/wiki/Trapping_rain_water
+ */
+public final class TrappingRainwater {
+
+ private TrappingRainwater() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ public static int trap(int[] height) {
+ int left = 0;
+ int right = height.length - 1;
+ int leftMax = 0;
+ int rightMax = 0;
+ int result = 0;
+
+ while (left < right) {
+ if (height[left] < height[right]) {
+ if (height[left] >= leftMax) {
+ leftMax = height[left];
+ } else {
+ result += leftMax - height[left];
+ }
+ left++;
+ } else {
+ if (height[right] >= rightMax) {
+ rightMax = height[right];
+ } else {
+ result += rightMax - height[right];
+ }
+ right--;
+ }
+ }
+ return result;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/stacks/TrappingRainwaterTest.java b/src/test/java/com/thealgorithms/stacks/TrappingRainwaterTest.java
new file mode 100644
index 000000000000..909be6cd46da
--- /dev/null
+++ b/src/test/java/com/thealgorithms/stacks/TrappingRainwaterTest.java
@@ -0,0 +1,38 @@
+package com.thealgorithms.stacks;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class TrappingRainwaterTest {
+
+ @Test
+ public void testExampleCase() {
+ int[] height = {4, 2, 0, 3, 2, 5};
+ assertEquals(9, TrappingRainwater.trap(height));
+ }
+
+ @Test
+ public void testNoTrapping() {
+ int[] height = {1, 2, 3, 4, 5};
+ assertEquals(0, TrappingRainwater.trap(height));
+ }
+
+ @Test
+ public void testFlatSurface() {
+ int[] height = {0, 0, 0, 0};
+ assertEquals(0, TrappingRainwater.trap(height));
+ }
+
+ @Test
+ public void testSymmetricPit() {
+ int[] height = {3, 0, 2, 0, 3};
+ assertEquals(7, TrappingRainwater.trap(height));
+ }
+
+ @Test
+ public void testSingleBar() {
+ int[] height = {5};
+ assertEquals(0, TrappingRainwater.trap(height));
+ }
+}
From 5a68ba93998c1ec4d0a201aba7e3d0ed942ae4c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?=
<55955273+khanhkhanhlele@users.noreply.github.com>
Date: Thu, 6 Nov 2025 17:40:34 +0700
Subject: [PATCH 156/272] chore: fix typos in some files (#7052)
Fix typos in some files
---
.../java/com/thealgorithms/datastructures/lists/README.md | 2 +-
.../java/com/thealgorithms/devutils/nodes/LargeTreeNode.java | 4 ++--
src/main/java/com/thealgorithms/others/CRCAlgorithm.java | 4 ++--
.../searches/RowColumnWiseSorted2dArrayBinarySearch.java | 2 +-
src/main/java/com/thealgorithms/sorts/LinkListSort.java | 2 +-
5 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/main/java/com/thealgorithms/datastructures/lists/README.md b/src/main/java/com/thealgorithms/datastructures/lists/README.md
index 5a19c3bfa990..5a0a43b923e1 100644
--- a/src/main/java/com/thealgorithms/datastructures/lists/README.md
+++ b/src/main/java/com/thealgorithms/datastructures/lists/README.md
@@ -28,6 +28,6 @@ The `next` variable points to the next node in the data structure and value stor
4. `CreateAndDetectLoop.java` : Create and detect a loop in a linked list.
5. `DoublyLinkedList.java` : A modification of singly linked list which has a `prev` pointer to point to the previous node.
6. `MergeKSortedLinkedlist.java` : Merges K sorted linked list with mergesort (mergesort is also the most efficient sorting algorithm for linked list).
-7. `RandomNode.java` : Selects a random node from given linked list and diplays it.
+7. `RandomNode.java` : Selects a random node from given linked list and displays it.
8. `SkipList.java` : Data Structure used for storing a sorted list of elements with help of a Linked list hierarchy that connects to subsequences of elements.
9. `TortoiseHareAlgo.java` : Finds the middle element of a linked list using the fast and slow pointer (Tortoise-Hare) algorithm.
diff --git a/src/main/java/com/thealgorithms/devutils/nodes/LargeTreeNode.java b/src/main/java/com/thealgorithms/devutils/nodes/LargeTreeNode.java
index 95d53ecb1f7a..d69288f72200 100644
--- a/src/main/java/com/thealgorithms/devutils/nodes/LargeTreeNode.java
+++ b/src/main/java/com/thealgorithms/devutils/nodes/LargeTreeNode.java
@@ -3,7 +3,7 @@
import java.util.Collection;
/**
- * {@link TreeNode} extension that holds a {@link Collection} of refrences to
+ * {@link TreeNode} extension that holds a {@link Collection} of references to
* child Nodes.
*
* @param The type of the data held in the Node.
@@ -18,7 +18,7 @@ public class LargeTreeNode extends TreeNode {
private Collection> childNodes;
/**
- * Empty contructor.
+ * Empty constructor.
*/
public LargeTreeNode() {
super();
diff --git a/src/main/java/com/thealgorithms/others/CRCAlgorithm.java b/src/main/java/com/thealgorithms/others/CRCAlgorithm.java
index 00ddc86be820..2d0be15e0a7b 100644
--- a/src/main/java/com/thealgorithms/others/CRCAlgorithm.java
+++ b/src/main/java/com/thealgorithms/others/CRCAlgorithm.java
@@ -95,7 +95,7 @@ public int getCorrectMess() {
/**
* Resets some of the object's values, used on the main function, so that it
- * can be re-used, in order not to waste too much memory and time, by
+ * can be reused, in order not to waste too much memory and time, by
* creating new objects.
*/
public void refactor() {
@@ -171,7 +171,7 @@ public void divideMessageWithP(boolean check) {
* Once the message is transmitted, some of it's elements, is possible to
* change from 1 to 0, or from 0 to 1, because of the Bit Error Rate (ber).
* For every element of the message, a random double number is created. If
- * that number is smaller than ber, then the spesific element changes. On
+ * that number is smaller than ber, then the specific element changes. On
* the other hand, if it's bigger than ber, it does not. Based on these
* changes. the boolean variable messageChanged, gets the value: true, or
* false.
diff --git a/src/main/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearch.java b/src/main/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearch.java
index b40c7554d84b..ecdcd36adf21 100644
--- a/src/main/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearch.java
+++ b/src/main/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearch.java
@@ -13,7 +13,7 @@
* In this two pointers are taken, the first points to the 0th row and the second one points to end
* column, and then the element corresponding to the pointers placed in the array is compared with
* the target that either its equal, greater or smaller than the target. If the element is equal to
- * the target, the co-ordinates of that element is returned i.e. an array of the two pointers will
+ * the target, the coordinates of that element is returned i.e. an array of the two pointers will
* be returned, else if the target is greater than corresponding element then the pointer pointing
* to the 0th row will be incremented by 1, else if the target is lesser than the corresponding
* element then the pointer pointing to the end column will be decremented by 1. And if the element
diff --git a/src/main/java/com/thealgorithms/sorts/LinkListSort.java b/src/main/java/com/thealgorithms/sorts/LinkListSort.java
index 800d78f36549..d8fd76a86236 100644
--- a/src/main/java/com/thealgorithms/sorts/LinkListSort.java
+++ b/src/main/java/com/thealgorithms/sorts/LinkListSort.java
@@ -106,7 +106,7 @@ public static boolean isSorted(int[] p, int option) {
// The given array and the expected array is checked if both are same then true
// is displayed else false is displayed
default:
- // default is used incase user puts a unauthorized value
+ // default is used in case user puts a unauthorized value
System.out.println("Wrong choice");
}
// Switch case is used to call the classes as per the user requirement
From 4951fb9ce23005150c0f32c3eadb615f1e96bbab Mon Sep 17 00:00:00 2001
From: Priyanshu Kumar Singh
Date: Thu, 6 Nov 2025 23:11:39 +0530
Subject: [PATCH 157/272] [FEAT] Add Kinematics (SUVAT) equations (#7053)
[FEAT] Add SUVAT equation for motion
Co-authored-by: Priyanshu1303d
---
.../com/thealgorithms/physics/Kinematics.java | 69 +++++++++++++++++++
.../thealgorithms/physics/KinematicsTest.java | 48 +++++++++++++
2 files changed, 117 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/physics/Kinematics.java
create mode 100644 src/test/java/com/thealgorithms/physics/KinematicsTest.java
diff --git a/src/main/java/com/thealgorithms/physics/Kinematics.java b/src/main/java/com/thealgorithms/physics/Kinematics.java
new file mode 100644
index 000000000000..d017fe787afd
--- /dev/null
+++ b/src/main/java/com/thealgorithms/physics/Kinematics.java
@@ -0,0 +1,69 @@
+package com.thealgorithms.physics;
+/**
+ * Implements the fundamental "SUVAT" equations for motion
+ * under constant acceleration.
+ *
+ * @author [Priyanshu Kumar Singh](https://github.com/Priyanshu1303d)
+ * @see Wikipedia
+ */
+public final class Kinematics {
+ private Kinematics() {
+ }
+
+ /**
+ * Calculates the final velocity (v) of an object.
+ * Formula: v = u + at
+ *
+ * @param u Initial velocity (m/s).
+ * @param a Constant acceleration (m/s^2).
+ * @param t Time elapsed (s).
+ * @return The final velocity (m/s).
+ */
+
+ public static double calculateFinalVelocity(double u, double a, double t) {
+ return u + a * t;
+ }
+
+ /**
+ * Calculates the displacement (s) of an object.
+ * Formula: s = ut + 0.5 * a * t^2
+ *
+ * @param u Initial velocity (m/s).
+ * @param a Constant acceleration (m/s^2).
+ * @param t Time elapsed (s).
+ * @return The displacement (m).
+ */
+
+ public static double calculateDisplacement(double u, double a, double t) {
+ return u * t + 0.5 * a * t * t;
+ }
+
+ /**
+ * Calculates the displacement (s) of an object.
+ * Formula: v^2 = u^2 + 2 * a * s
+ *
+ * @param u Initial velocity (m/s).
+ * @param a Constant acceleration (m/s^2).
+ * @param s Displacement (m).
+ * @return The final velocity squared (m/s)^2.
+ */
+
+ public static double calculateFinalVelocitySquared(double u, double a, double s) {
+ return u * u + 2 * a * s;
+ }
+
+ /**
+ * Calculates the displacement (s) using the average velocity.
+ * Formula: s = (u + v) / 2 * t
+ *
+ * @param u Initial velocity (m/s).
+ * @param v Final velocity (m/s).
+ * @param t Time elapsed (s).
+ * @return The displacement (m).
+ */
+
+ public static double calculateDisplacementFromVelocities(double u, double v, double t) {
+ double velocitySum = u + v;
+ return velocitySum / 2 * t;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/physics/KinematicsTest.java b/src/test/java/com/thealgorithms/physics/KinematicsTest.java
new file mode 100644
index 000000000000..c5274b0814a7
--- /dev/null
+++ b/src/test/java/com/thealgorithms/physics/KinematicsTest.java
@@ -0,0 +1,48 @@
+package com.thealgorithms.physics;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the Kinematics utility class.
+ */
+
+public final class KinematicsTest {
+ // A small tolerance for comparing floating-point numbers
+ private static final double DELTA = 1e-9;
+ @Test
+ @DisplayName("Test final velocity: v = u + at")
+ void testCalculateFinalVelocity() {
+ assertEquals(20.0, Kinematics.calculateFinalVelocity(10.0, 2.0, 5.0), DELTA);
+ }
+
+ @Test
+ @DisplayName("Test displacement: s = ut + 0.5at^2")
+ void testCalculateDisplacement() {
+ assertEquals(75.0, Kinematics.calculateDisplacement(10.0, 2.0, 5.0), DELTA);
+ }
+
+ @Test
+ @DisplayName("Test final velocity squared: v^2 = u^2 + 2as")
+ void testCalculateFinalVelocitySquared() {
+ assertEquals(400.0, Kinematics.calculateFinalVelocitySquared(10.0, 2.0, 75.0), DELTA);
+ }
+
+ @Test
+ @DisplayName("Test displacement from average velocity: s = (u+v)/2 * t")
+ void testCalculateDisplacementFromVelocities() {
+ assertEquals(75.0, Kinematics.calculateDisplacementFromVelocities(10.0, 20.0, 5.0), DELTA);
+ }
+
+ @Test
+ @DisplayName("Test with negative acceleration (deceleration)")
+ void testDeceleration() {
+ assertEquals(10.0, Kinematics.calculateFinalVelocity(30.0, -4.0, 5.0), DELTA);
+ assertEquals(100.0, Kinematics.calculateDisplacement(30.0, -4.0, 5.0), DELTA);
+
+ assertEquals(100.0, Kinematics.calculateFinalVelocitySquared(30.0, -4.0, 100.0), DELTA);
+ assertEquals(100.0, Kinematics.calculateDisplacementFromVelocities(30.0, 10.0, 5.0), DELTA);
+ }
+}
From 2588af02057eff98541d859a9a90f30b91268457 Mon Sep 17 00:00:00 2001
From: PRINCE PATEL
Date: Fri, 7 Nov 2025 16:02:18 +0530
Subject: [PATCH 158/272] fix: Correct typo in ExponentialSearch filename
(#7056)
---
.../searches/{ExponentalSearch.java => ExponentialSearch.java} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename src/main/java/com/thealgorithms/searches/{ExponentalSearch.java => ExponentialSearch.java} (100%)
diff --git a/src/main/java/com/thealgorithms/searches/ExponentalSearch.java b/src/main/java/com/thealgorithms/searches/ExponentialSearch.java
similarity index 100%
rename from src/main/java/com/thealgorithms/searches/ExponentalSearch.java
rename to src/main/java/com/thealgorithms/searches/ExponentialSearch.java
From 0a5516569231f5c6daa48f9397447cf063c3d6ec Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 11 Nov 2025 13:03:51 +0100
Subject: [PATCH 159/272] chore(deps): bump
com.mebigfatguy.fb-contrib:fb-contrib from 7.6.15 to 7.7.0 (#7060)
* chore(deps): bump com.mebigfatguy.fb-contrib:fb-contrib
Bumps [com.mebigfatguy.fb-contrib:fb-contrib](https://github.com/mebigfatguy/fb-contrib) from 7.6.15 to 7.7.0.
- [Commits](https://github.com/mebigfatguy/fb-contrib/commits/v7.7.0)
---
updated-dependencies:
- dependency-name: com.mebigfatguy.fb-contrib:fb-contrib
dependency-version: 7.7.0
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
* fix: suppress new warnings
---------
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: vil02 <65706193+vil02@users.noreply.github.com>
---
pom.xml | 2 +-
spotbugs-exclude.xml | 6 ++++++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 7e936967208b..e99c8762ea3d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -127,7 +127,7 @@
com.mebigfatguy.fb-contrib
fb-contrib
- 7.6.15
+ 7.7.0
com.h3xstream.findsecbugs
diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml
index d2e094556d61..3e2f1ff84ca8 100644
--- a/spotbugs-exclude.xml
+++ b/spotbugs-exclude.xml
@@ -201,6 +201,12 @@
+
+
+
+
+
+
From b709941eb688f5c5d4e442eb9ab64568c234814f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 11 Nov 2025 22:30:27 +0100
Subject: [PATCH 160/272] chore(deps): bump com.puppycrawl.tools:checkstyle
from 12.1.1 to 12.1.2 (#7063)
Bumps [com.puppycrawl.tools:checkstyle](https://github.com/checkstyle/checkstyle) from 12.1.1 to 12.1.2.
- [Release notes](https://github.com/checkstyle/checkstyle/releases)
- [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-12.1.1...checkstyle-12.1.2)
---
updated-dependencies:
- dependency-name: com.puppycrawl.tools:checkstyle
dependency-version: 12.1.2
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index e99c8762ea3d..6126bbe4d6c5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -112,7 +112,7 @@
com.puppycrawl.tools
checkstyle
- 12.1.1
+ 12.1.2
From a008cc2b0889ed51bf47e673e5f056e97f64cae1 Mon Sep 17 00:00:00 2001
From: Deniz Altunkapan
Date: Wed, 12 Nov 2025 14:22:21 +0100
Subject: [PATCH 161/272] Update DIRECTORY.md (#6809)
Co-authored-by: DenizAltunkapan
---
DIRECTORY.md | 57 +++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 52 insertions(+), 5 deletions(-)
diff --git a/DIRECTORY.md b/DIRECTORY.md
index eca2453fad0f..f15d65c18c3f 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -13,6 +13,7 @@
- 📄 [AllPathsFromSourceToTarget](src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java)
- 📄 [ArrayCombination](src/main/java/com/thealgorithms/backtracking/ArrayCombination.java)
- 📄 [Combination](src/main/java/com/thealgorithms/backtracking/Combination.java)
+ - 📄 [CombinationSum](src/main/java/com/thealgorithms/backtracking/CombinationSum.java)
- 📄 [CrosswordSolver](src/main/java/com/thealgorithms/backtracking/CrosswordSolver.java)
- 📄 [FloodFill](src/main/java/com/thealgorithms/backtracking/FloodFill.java)
- 📄 [KnightsTour](src/main/java/com/thealgorithms/backtracking/KnightsTour.java)
@@ -28,6 +29,7 @@
- 📁 **bitmanipulation**
- 📄 [BcdConversion](src/main/java/com/thealgorithms/bitmanipulation/BcdConversion.java)
- 📄 [BinaryPalindromeCheck](src/main/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheck.java)
+ - 📄 [BitRotate](src/main/java/com/thealgorithms/bitmanipulation/BitRotate.java)
- 📄 [BitSwap](src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java)
- 📄 [BitwiseGCD](src/main/java/com/thealgorithms/bitmanipulation/BitwiseGCD.java)
- 📄 [BooleanAlgebraGates](src/main/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGates.java)
@@ -93,6 +95,12 @@
- 📄 [LFSR](src/main/java/com/thealgorithms/ciphers/a5/LFSR.java)
- 📄 [Utils](src/main/java/com/thealgorithms/ciphers/a5/Utils.java)
- 📁 **compression**
+ - 📄 [ArithmeticCoding](src/main/java/com/thealgorithms/compression/ArithmeticCoding.java)
+ - 📄 [BurrowsWheelerTransform](src/main/java/com/thealgorithms/compression/BurrowsWheelerTransform.java)
+ - 📄 [LZ77](src/main/java/com/thealgorithms/compression/LZ77.java)
+ - 📄 [LZ78](src/main/java/com/thealgorithms/compression/LZ78.java)
+ - 📄 [LZW](src/main/java/com/thealgorithms/compression/LZW.java)
+ - 📄 [MoveToFront](src/main/java/com/thealgorithms/compression/MoveToFront.java)
- 📄 [RunLengthEncoding](src/main/java/com/thealgorithms/compression/RunLengthEncoding.java)
- 📄 [ShannonFano](src/main/java/com/thealgorithms/compression/ShannonFano.java)
- 📁 **conversions**
@@ -173,7 +181,6 @@
- 📄 [FordFulkerson](src/main/java/com/thealgorithms/datastructures/graphs/FordFulkerson.java)
- 📄 [Graphs](src/main/java/com/thealgorithms/datastructures/graphs/Graphs.java)
- 📄 [HamiltonianCycle](src/main/java/com/thealgorithms/datastructures/graphs/HamiltonianCycle.java)
- - 📄 [HierholzerAlgorithm](src/main/java/com/thealgorithms/graph/HierholzerAlgorithm.java)
- 📄 [JohnsonsAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithm.java)
- 📄 [KahnsAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/KahnsAlgorithm.java)
- 📄 [Kosaraju](src/main/java/com/thealgorithms/datastructures/graphs/Kosaraju.java)
@@ -358,8 +365,10 @@
- 📄 [WildcardMatching](src/main/java/com/thealgorithms/dynamicprogramming/WildcardMatching.java)
- 📄 [WineProblem](src/main/java/com/thealgorithms/dynamicprogramming/WineProblem.java)
- 📁 **geometry**
+ - 📄 [BentleyOttmann](src/main/java/com/thealgorithms/geometry/BentleyOttmann.java)
- 📄 [BresenhamLine](src/main/java/com/thealgorithms/geometry/BresenhamLine.java)
- 📄 [ConvexHull](src/main/java/com/thealgorithms/geometry/ConvexHull.java)
+ - 📄 [DDALine](src/main/java/com/thealgorithms/geometry/DDALine.java)
- 📄 [GrahamScan](src/main/java/com/thealgorithms/geometry/GrahamScan.java)
- 📄 [Haversine](src/main/java/com/thealgorithms/geometry/Haversine.java)
- 📄 [MidpointCircle](src/main/java/com/thealgorithms/geometry/MidpointCircle.java)
@@ -372,10 +381,13 @@
- 📄 [Dinic](src/main/java/com/thealgorithms/graph/Dinic.java)
- 📄 [Edmonds](src/main/java/com/thealgorithms/graph/Edmonds.java)
- 📄 [EdmondsKarp](src/main/java/com/thealgorithms/graph/EdmondsKarp.java)
+ - 📄 [HierholzerAlgorithm](src/main/java/com/thealgorithms/graph/HierholzerAlgorithm.java)
+ - 📄 [HierholzerEulerianPath](src/main/java/com/thealgorithms/graph/HierholzerEulerianPath.java)
- 📄 [HopcroftKarp](src/main/java/com/thealgorithms/graph/HopcroftKarp.java)
- 📄 [HungarianAlgorithm](src/main/java/com/thealgorithms/graph/HungarianAlgorithm.java)
- 📄 [PredecessorConstrainedDfs](src/main/java/com/thealgorithms/graph/PredecessorConstrainedDfs.java)
- 📄 [PushRelabel](src/main/java/com/thealgorithms/graph/PushRelabel.java)
+ - 📄 [StoerWagner](src/main/java/com/thealgorithms/graph/StoerWagner.java)
- 📄 [StronglyConnectedComponentOptimized](src/main/java/com/thealgorithms/graph/StronglyConnectedComponentOptimized.java)
- 📄 [TravelingSalesman](src/main/java/com/thealgorithms/graph/TravelingSalesman.java)
- 📄 [YensKShortestPaths](src/main/java/com/thealgorithms/graph/YensKShortestPaths.java)
@@ -420,6 +432,7 @@
- 📄 [BinomialCoefficient](src/main/java/com/thealgorithms/maths/BinomialCoefficient.java)
- 📄 [CatalanNumbers](src/main/java/com/thealgorithms/maths/CatalanNumbers.java)
- 📄 [Ceil](src/main/java/com/thealgorithms/maths/Ceil.java)
+ - 📄 [ChebyshevIteration](src/main/java/com/thealgorithms/maths/ChebyshevIteration.java)
- 📄 [ChineseRemainderTheorem](src/main/java/com/thealgorithms/maths/ChineseRemainderTheorem.java)
- 📄 [CircularConvolutionFFT](src/main/java/com/thealgorithms/maths/CircularConvolutionFFT.java)
- 📄 [CollatzConjecture](src/main/java/com/thealgorithms/maths/CollatzConjecture.java)
@@ -478,6 +491,7 @@
- 📄 [Median](src/main/java/com/thealgorithms/maths/Median.java)
- 📄 [MinValue](src/main/java/com/thealgorithms/maths/MinValue.java)
- 📄 [Mode](src/main/java/com/thealgorithms/maths/Mode.java)
+ - 📄 [Neville](src/main/java/com/thealgorithms/maths/Neville.java)
- 📄 [NonRepeatingElement](src/main/java/com/thealgorithms/maths/NonRepeatingElement.java)
- 📄 [NthUglyNumber](src/main/java/com/thealgorithms/maths/NthUglyNumber.java)
- 📄 [NumberOfDigits](src/main/java/com/thealgorithms/maths/NumberOfDigits.java)
@@ -531,6 +545,7 @@
- 📄 [ZellersCongruence](src/main/java/com/thealgorithms/maths/ZellersCongruence.java)
- 📁 **matrix**
- 📄 [InverseOfMatrix](src/main/java/com/thealgorithms/matrix/InverseOfMatrix.java)
+ - 📄 [LUDecomposition](src/main/java/com/thealgorithms/matrix/LUDecomposition.java)
- 📄 [MatrixMultiplication](src/main/java/com/thealgorithms/matrix/MatrixMultiplication.java)
- 📄 [MatrixRank](src/main/java/com/thealgorithms/matrix/MatrixRank.java)
- 📄 [MatrixTranspose](src/main/java/com/thealgorithms/matrix/MatrixTranspose.java)
@@ -591,7 +606,6 @@
- 📄 [PageRank](src/main/java/com/thealgorithms/others/PageRank.java)
- 📄 [PasswordGen](src/main/java/com/thealgorithms/others/PasswordGen.java)
- 📄 [PerlinNoise](src/main/java/com/thealgorithms/others/PerlinNoise.java)
- - 📄 [PrintAMatrixInSpiralOrder](src/main/java/com/thealgorithms/others/PrintAMatrixInSpiralOrder.java)
- 📄 [QueueUsingTwoStacks](src/main/java/com/thealgorithms/others/QueueUsingTwoStacks.java)
- 📄 [SkylineProblem](src/main/java/com/thealgorithms/others/SkylineProblem.java)
- 📄 [TwoPointers](src/main/java/com/thealgorithms/others/TwoPointers.java)
@@ -599,7 +613,14 @@
- 📁 **cn**
- 📄 [HammingDistance](src/main/java/com/thealgorithms/others/cn/HammingDistance.java)
- 📁 **physics**
+ - 📄 [CoulombsLaw](src/main/java/com/thealgorithms/physics/CoulombsLaw.java)
+ - 📄 [DampedOscillator](src/main/java/com/thealgorithms/physics/DampedOscillator.java)
+ - 📄 [ElasticCollision2D](src/main/java/com/thealgorithms/physics/ElasticCollision2D.java)
+ - 📄 [Gravitation](src/main/java/com/thealgorithms/physics/Gravitation.java)
- 📄 [GroundToGroundProjectileMotion](src/main/java/com/thealgorithms/physics/GroundToGroundProjectileMotion.java)
+ - 📄 [Kinematics](src/main/java/com/thealgorithms/physics/Kinematics.java)
+ - 📄 [ProjectileMotion](src/main/java/com/thealgorithms/physics/ProjectileMotion.java)
+ - 📄 [SimplePendulumRK4](src/main/java/com/thealgorithms/physics/SimplePendulumRK4.java)
- 📁 **puzzlesandgames**
- 📄 [Sudoku](src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java)
- 📄 [TowerOfHanoi](src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java)
@@ -649,7 +670,7 @@
- 📄 [BoyerMoore](src/main/java/com/thealgorithms/searches/BoyerMoore.java)
- 📄 [BreadthFirstSearch](src/main/java/com/thealgorithms/searches/BreadthFirstSearch.java)
- 📄 [DepthFirstSearch](src/main/java/com/thealgorithms/searches/DepthFirstSearch.java)
- - 📄 [ExponentalSearch](src/main/java/com/thealgorithms/searches/ExponentalSearch.java)
+ - 📄 [ExponentialSearch](src/main/java/com/thealgorithms/searches/ExponentialSearch.java)
- 📄 [FibonacciSearch](src/main/java/com/thealgorithms/searches/FibonacciSearch.java)
- 📄 [HowManyTimesRotated](src/main/java/com/thealgorithms/searches/HowManyTimesRotated.java)
- 📄 [InterpolationSearch](src/main/java/com/thealgorithms/searches/InterpolationSearch.java)
@@ -758,6 +779,7 @@
- 📄 [SortStack](src/main/java/com/thealgorithms/stacks/SortStack.java)
- 📄 [StackPostfixNotation](src/main/java/com/thealgorithms/stacks/StackPostfixNotation.java)
- 📄 [StackUsingTwoQueues](src/main/java/com/thealgorithms/stacks/StackUsingTwoQueues.java)
+ - 📄 [TrappingRainwater](src/main/java/com/thealgorithms/stacks/TrappingRainwater.java)
- 📁 **strings**
- 📄 [AhoCorasick](src/main/java/com/thealgorithms/strings/AhoCorasick.java)
- 📄 [Alphabetical](src/main/java/com/thealgorithms/strings/Alphabetical.java)
@@ -808,6 +830,7 @@
- 📁 **backtracking**
- 📄 [AllPathsFromSourceToTargetTest](src/test/java/com/thealgorithms/backtracking/AllPathsFromSourceToTargetTest.java)
- 📄 [ArrayCombinationTest](src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java)
+ - 📄 [CombinationSumTest](src/test/java/com/thealgorithms/backtracking/CombinationSumTest.java)
- 📄 [CombinationTest](src/test/java/com/thealgorithms/backtracking/CombinationTest.java)
- 📄 [CrosswordSolverTest](src/test/java/com/thealgorithms/backtracking/CrosswordSolverTest.java)
- 📄 [FloodFillTest](src/test/java/com/thealgorithms/backtracking/FloodFillTest.java)
@@ -824,6 +847,7 @@
- 📁 **bitmanipulation**
- 📄 [BcdConversionTest](src/test/java/com/thealgorithms/bitmanipulation/BcdConversionTest.java)
- 📄 [BinaryPalindromeCheckTest](src/test/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheckTest.java)
+ - 📄 [BitRotateTest](src/test/java/com/thealgorithms/bitmanipulation/BitRotateTest.java)
- 📄 [BitSwapTest](src/test/java/com/thealgorithms/bitmanipulation/BitSwapTest.java)
- 📄 [BitwiseGCDTest](src/test/java/com/thealgorithms/bitmanipulation/BitwiseGCDTest.java)
- 📄 [BooleanAlgebraGatesTest](src/test/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGatesTest.java)
@@ -884,6 +908,12 @@
- 📄 [A5KeyStreamGeneratorTest](src/test/java/com/thealgorithms/ciphers/a5/A5KeyStreamGeneratorTest.java)
- 📄 [LFSRTest](src/test/java/com/thealgorithms/ciphers/a5/LFSRTest.java)
- 📁 **compression**
+ - 📄 [ArithmeticCodingTest](src/test/java/com/thealgorithms/compression/ArithmeticCodingTest.java)
+ - 📄 [BurrowsWheelerTransformTest](src/test/java/com/thealgorithms/compression/BurrowsWheelerTransformTest.java)
+ - 📄 [LZ77Test](src/test/java/com/thealgorithms/compression/LZ77Test.java)
+ - 📄 [LZ78Test](src/test/java/com/thealgorithms/compression/LZ78Test.java)
+ - 📄 [LZWTest](src/test/java/com/thealgorithms/compression/LZWTest.java)
+ - 📄 [MoveToFrontTest](src/test/java/com/thealgorithms/compression/MoveToFrontTest.java)
- 📄 [RunLengthEncodingTest](src/test/java/com/thealgorithms/compression/RunLengthEncodingTest.java)
- 📄 [ShannonFanoTest](src/test/java/com/thealgorithms/compression/ShannonFanoTest.java)
- 📁 **conversions**
@@ -1114,8 +1144,10 @@
- 📄 [WildcardMatchingTest](src/test/java/com/thealgorithms/dynamicprogramming/WildcardMatchingTest.java)
- 📄 [WineProblemTest](src/test/java/com/thealgorithms/dynamicprogramming/WineProblemTest.java)
- 📁 **geometry**
+ - 📄 [BentleyOttmannTest](src/test/java/com/thealgorithms/geometry/BentleyOttmannTest.java)
- 📄 [BresenhamLineTest](src/test/java/com/thealgorithms/geometry/BresenhamLineTest.java)
- 📄 [ConvexHullTest](src/test/java/com/thealgorithms/geometry/ConvexHullTest.java)
+ - 📄 [DDALineTest](src/test/java/com/thealgorithms/geometry/DDALineTest.java)
- 📄 [GrahamScanTest](src/test/java/com/thealgorithms/geometry/GrahamScanTest.java)
- 📄 [HaversineTest](src/test/java/com/thealgorithms/geometry/HaversineTest.java)
- 📄 [MidpointCircleTest](src/test/java/com/thealgorithms/geometry/MidpointCircleTest.java)
@@ -1128,9 +1160,13 @@
- 📄 [DinicTest](src/test/java/com/thealgorithms/graph/DinicTest.java)
- 📄 [EdmondsKarpTest](src/test/java/com/thealgorithms/graph/EdmondsKarpTest.java)
- 📄 [EdmondsTest](src/test/java/com/thealgorithms/graph/EdmondsTest.java)
+ - 📄 [HierholzerAlgorithmTest](src/test/java/com/thealgorithms/graph/HierholzerAlgorithmTest.java)
+ - 📄 [HierholzerEulerianPathTest](src/test/java/com/thealgorithms/graph/HierholzerEulerianPathTest.java)
- 📄 [HopcroftKarpTest](src/test/java/com/thealgorithms/graph/HopcroftKarpTest.java)
+ - 📄 [HungarianAlgorithmTest](src/test/java/com/thealgorithms/graph/HungarianAlgorithmTest.java)
- 📄 [PredecessorConstrainedDfsTest](src/test/java/com/thealgorithms/graph/PredecessorConstrainedDfsTest.java)
- 📄 [PushRelabelTest](src/test/java/com/thealgorithms/graph/PushRelabelTest.java)
+ - 📄 [StoerWagnerTest](src/test/java/com/thealgorithms/graph/StoerWagnerTest.java)
- 📄 [StronglyConnectedComponentOptimizedTest](src/test/java/com/thealgorithms/graph/StronglyConnectedComponentOptimizedTest.java)
- 📄 [TravelingSalesmanTest](src/test/java/com/thealgorithms/graph/TravelingSalesmanTest.java)
- 📄 [YensKShortestPathsTest](src/test/java/com/thealgorithms/graph/YensKShortestPathsTest.java)
@@ -1172,6 +1208,7 @@
- 📄 [BinomialCoefficientTest](src/test/java/com/thealgorithms/maths/BinomialCoefficientTest.java)
- 📄 [CatalanNumbersTest](src/test/java/com/thealgorithms/maths/CatalanNumbersTest.java)
- 📄 [CeilTest](src/test/java/com/thealgorithms/maths/CeilTest.java)
+ - 📄 [ChebyshevIterationTest](src/test/java/com/thealgorithms/maths/ChebyshevIterationTest.java)
- 📄 [ChineseRemainderTheoremTest](src/test/java/com/thealgorithms/maths/ChineseRemainderTheoremTest.java)
- 📄 [CollatzConjectureTest](src/test/java/com/thealgorithms/maths/CollatzConjectureTest.java)
- 📄 [CombinationsTest](src/test/java/com/thealgorithms/maths/CombinationsTest.java)
@@ -1211,6 +1248,7 @@
- 📄 [HarshadNumberTest](src/test/java/com/thealgorithms/maths/HarshadNumberTest.java)
- 📄 [HeronsFormulaTest](src/test/java/com/thealgorithms/maths/HeronsFormulaTest.java)
- 📄 [JosephusProblemTest](src/test/java/com/thealgorithms/maths/JosephusProblemTest.java)
+ - 📄 [JugglerSequenceTest](src/test/java/com/thealgorithms/maths/JugglerSequenceTest.java)
- 📄 [KaprekarNumbersTest](src/test/java/com/thealgorithms/maths/KaprekarNumbersTest.java)
- 📄 [KaratsubaMultiplicationTest](src/test/java/com/thealgorithms/maths/KaratsubaMultiplicationTest.java)
- 📄 [KeithNumberTest](src/test/java/com/thealgorithms/maths/KeithNumberTest.java)
@@ -1226,6 +1264,7 @@
- 📄 [MedianTest](src/test/java/com/thealgorithms/maths/MedianTest.java)
- 📄 [MinValueTest](src/test/java/com/thealgorithms/maths/MinValueTest.java)
- 📄 [ModeTest](src/test/java/com/thealgorithms/maths/ModeTest.java)
+ - 📄 [NevilleTest](src/test/java/com/thealgorithms/maths/NevilleTest.java)
- 📄 [NonRepeatingElementTest](src/test/java/com/thealgorithms/maths/NonRepeatingElementTest.java)
- 📄 [NthUglyNumberTest](src/test/java/com/thealgorithms/maths/NthUglyNumberTest.java)
- 📄 [NumberOfDigitsTest](src/test/java/com/thealgorithms/maths/NumberOfDigitsTest.java)
@@ -1275,14 +1314,15 @@
- 📄 [PrimeFactorizationTest](src/test/java/com/thealgorithms/maths/prime/PrimeFactorizationTest.java)
- 📁 **matrix**
- 📄 [InverseOfMatrixTest](src/test/java/com/thealgorithms/matrix/InverseOfMatrixTest.java)
+ - 📄 [LUDecompositionTest](src/test/java/com/thealgorithms/matrix/LUDecompositionTest.java)
- 📄 [MatrixMultiplicationTest](src/test/java/com/thealgorithms/matrix/MatrixMultiplicationTest.java)
- 📄 [MatrixRankTest](src/test/java/com/thealgorithms/matrix/MatrixRankTest.java)
- 📄 [MatrixTransposeTest](src/test/java/com/thealgorithms/matrix/MatrixTransposeTest.java)
- 📄 [MatrixUtilTest](src/test/java/com/thealgorithms/matrix/MatrixUtilTest.java)
- 📄 [MedianOfMatrixTest](src/test/java/com/thealgorithms/matrix/MedianOfMatrixTest.java)
- 📄 [MirrorOfMatrixTest](src/test/java/com/thealgorithms/matrix/MirrorOfMatrixTest.java)
+ - 📄 [PrintAMatrixInSpiralOrderTest](src/test/java/com/thealgorithms/matrix/PrintAMatrixInSpiralOrderTest.java)
- 📄 [SolveSystemTest](src/test/java/com/thealgorithms/matrix/SolveSystemTest.java)
- - 📄 [TestPrintMatrixInSpiralOrder](src/test/java/com/thealgorithms/matrix/TestPrintMatrixInSpiralOrder.java)
- 📁 **misc**
- 📄 [ColorContrastRatioTest](src/test/java/com/thealgorithms/misc/ColorContrastRatioTest.java)
- 📄 [MapReduceTest](src/test/java/com/thealgorithms/misc/MapReduceTest.java)
@@ -1323,13 +1363,19 @@
- 📄 [PerlinNoiseTest](src/test/java/com/thealgorithms/others/PerlinNoiseTest.java)
- 📄 [QueueUsingTwoStacksTest](src/test/java/com/thealgorithms/others/QueueUsingTwoStacksTest.java)
- 📄 [SkylineProblemTest](src/test/java/com/thealgorithms/others/SkylineProblemTest.java)
- - 📄 [TestPrintMatrixInSpiralOrder](src/test/java/com/thealgorithms/others/TestPrintMatrixInSpiralOrder.java)
- 📄 [TwoPointersTest](src/test/java/com/thealgorithms/others/TwoPointersTest.java)
- 📄 [WorstFitCPUTest](src/test/java/com/thealgorithms/others/WorstFitCPUTest.java)
- 📁 **cn**
- 📄 [HammingDistanceTest](src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java)
- 📁 **physics**
+ - 📄 [CoulombsLawTest](src/test/java/com/thealgorithms/physics/CoulombsLawTest.java)
+ - 📄 [DampedOscillatorTest](src/test/java/com/thealgorithms/physics/DampedOscillatorTest.java)
+ - 📄 [ElasticCollision2DTest](src/test/java/com/thealgorithms/physics/ElasticCollision2DTest.java)
+ - 📄 [GravitationTest](src/test/java/com/thealgorithms/physics/GravitationTest.java)
- 📄 [GroundToGroundProjectileMotionTest](src/test/java/com/thealgorithms/physics/GroundToGroundProjectileMotionTest.java)
+ - 📄 [KinematicsTest](src/test/java/com/thealgorithms/physics/KinematicsTest.java)
+ - 📄 [ProjectileMotionTest](src/test/java/com/thealgorithms/physics/ProjectileMotionTest.java)
+ - 📄 [SimplePendulumRK4Test](src/test/java/com/thealgorithms/physics/SimplePendulumRK4Test.java)
- 📁 **puzzlesandgames**
- 📄 [SudokuTest](src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java)
- 📄 [TowerOfHanoiTest](src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java)
@@ -1487,6 +1533,7 @@
- 📄 [SortStackTest](src/test/java/com/thealgorithms/stacks/SortStackTest.java)
- 📄 [StackPostfixNotationTest](src/test/java/com/thealgorithms/stacks/StackPostfixNotationTest.java)
- 📄 [StackUsingTwoQueuesTest](src/test/java/com/thealgorithms/stacks/StackUsingTwoQueuesTest.java)
+ - 📄 [TrappingRainwaterTest](src/test/java/com/thealgorithms/stacks/TrappingRainwaterTest.java)
- 📁 **strings**
- 📄 [AhoCorasickTest](src/test/java/com/thealgorithms/strings/AhoCorasickTest.java)
- 📄 [AlphabeticalTest](src/test/java/com/thealgorithms/strings/AlphabeticalTest.java)
From 8a339ef2e2ad0ec7bc3fb9ce8076fc33a61d548e Mon Sep 17 00:00:00 2001
From: Krishna
Date: Sat, 15 Nov 2025 14:52:36 +0530
Subject: [PATCH 162/272] Add Temperature Conversion Utility (#7066)
- Implements conversions between Celsius, Fahrenheit, and Kelvin
- Includes all 6 conversion methods
- Adds comprehensive unit tests with edge cases
- Fixes #6936
---
.../conversions/TemperatureConverter.java | 46 ++++++++++++++++
.../conversions/TemperatureConverterTest.java | 54 +++++++++++++++++++
2 files changed, 100 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/conversions/TemperatureConverter.java
create mode 100644 src/test/java/com/thealgorithms/conversions/TemperatureConverterTest.java
diff --git a/src/main/java/com/thealgorithms/conversions/TemperatureConverter.java b/src/main/java/com/thealgorithms/conversions/TemperatureConverter.java
new file mode 100644
index 000000000000..901db17c665d
--- /dev/null
+++ b/src/main/java/com/thealgorithms/conversions/TemperatureConverter.java
@@ -0,0 +1,46 @@
+package com.thealgorithms.conversions;
+
+/**
+ * A utility class to convert between different temperature units.
+ *
+ * This class supports conversions between the following units:
+ *
+ * - Celsius
+ * - Fahrenheit
+ * - Kelvin
+ *
+ *
+ * This class is final and cannot be instantiated.
+ *
+ * @author krishna-medapati (https://github.com/krishna-medapati)
+ * @see Wikipedia: Temperature Conversion
+ */
+public final class TemperatureConverter {
+
+ private TemperatureConverter() {
+ }
+
+ public static double celsiusToFahrenheit(double celsius) {
+ return celsius * 9.0 / 5.0 + 32.0;
+ }
+
+ public static double celsiusToKelvin(double celsius) {
+ return celsius + 273.15;
+ }
+
+ public static double fahrenheitToCelsius(double fahrenheit) {
+ return (fahrenheit - 32.0) * 5.0 / 9.0;
+ }
+
+ public static double fahrenheitToKelvin(double fahrenheit) {
+ return (fahrenheit - 32.0) * 5.0 / 9.0 + 273.15;
+ }
+
+ public static double kelvinToCelsius(double kelvin) {
+ return kelvin - 273.15;
+ }
+
+ public static double kelvinToFahrenheit(double kelvin) {
+ return (kelvin - 273.15) * 9.0 / 5.0 + 32.0;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/conversions/TemperatureConverterTest.java b/src/test/java/com/thealgorithms/conversions/TemperatureConverterTest.java
new file mode 100644
index 000000000000..24d55b706f36
--- /dev/null
+++ b/src/test/java/com/thealgorithms/conversions/TemperatureConverterTest.java
@@ -0,0 +1,54 @@
+package com.thealgorithms.conversions;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+class TemperatureConverterTest {
+
+ private static final double DELTA = 0.01;
+
+ @Test
+ void testCelsiusToFahrenheit() {
+ assertEquals(32.0, TemperatureConverter.celsiusToFahrenheit(0.0), DELTA);
+ assertEquals(212.0, TemperatureConverter.celsiusToFahrenheit(100.0), DELTA);
+ assertEquals(-40.0, TemperatureConverter.celsiusToFahrenheit(-40.0), DELTA);
+ assertEquals(98.6, TemperatureConverter.celsiusToFahrenheit(37.0), DELTA);
+ }
+
+ @Test
+ void testCelsiusToKelvin() {
+ assertEquals(273.15, TemperatureConverter.celsiusToKelvin(0.0), DELTA);
+ assertEquals(373.15, TemperatureConverter.celsiusToKelvin(100.0), DELTA);
+ assertEquals(233.15, TemperatureConverter.celsiusToKelvin(-40.0), DELTA);
+ }
+
+ @Test
+ void testFahrenheitToCelsius() {
+ assertEquals(0.0, TemperatureConverter.fahrenheitToCelsius(32.0), DELTA);
+ assertEquals(100.0, TemperatureConverter.fahrenheitToCelsius(212.0), DELTA);
+ assertEquals(-40.0, TemperatureConverter.fahrenheitToCelsius(-40.0), DELTA);
+ assertEquals(37.0, TemperatureConverter.fahrenheitToCelsius(98.6), DELTA);
+ }
+
+ @Test
+ void testFahrenheitToKelvin() {
+ assertEquals(273.15, TemperatureConverter.fahrenheitToKelvin(32.0), DELTA);
+ assertEquals(373.15, TemperatureConverter.fahrenheitToKelvin(212.0), DELTA);
+ assertEquals(233.15, TemperatureConverter.fahrenheitToKelvin(-40.0), DELTA);
+ }
+
+ @Test
+ void testKelvinToCelsius() {
+ assertEquals(0.0, TemperatureConverter.kelvinToCelsius(273.15), DELTA);
+ assertEquals(100.0, TemperatureConverter.kelvinToCelsius(373.15), DELTA);
+ assertEquals(-273.15, TemperatureConverter.kelvinToCelsius(0.0), DELTA);
+ }
+
+ @Test
+ void testKelvinToFahrenheit() {
+ assertEquals(32.0, TemperatureConverter.kelvinToFahrenheit(273.15), DELTA);
+ assertEquals(212.0, TemperatureConverter.kelvinToFahrenheit(373.15), DELTA);
+ assertEquals(-40.0, TemperatureConverter.kelvinToFahrenheit(233.15), DELTA);
+ }
+}
From 98eecb9f16003e612ad8d84ed6f3c78ae10c7005 Mon Sep 17 00:00:00 2001
From: Taranjeet Singh Kalsi
Date: Sat, 15 Nov 2025 15:02:06 +0530
Subject: [PATCH 163/272] Added program to check Smith number (#6955)
added smith number program
---
.../com/thealgorithms/maths/SmithNumber.java | 52 +++++++++++++++++++
.../thealgorithms/maths/SmithNumberTest.java | 22 ++++++++
2 files changed, 74 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/maths/SmithNumber.java
create mode 100644 src/test/java/com/thealgorithms/maths/SmithNumberTest.java
diff --git a/src/main/java/com/thealgorithms/maths/SmithNumber.java b/src/main/java/com/thealgorithms/maths/SmithNumber.java
new file mode 100644
index 000000000000..c06e0023d9bb
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/SmithNumber.java
@@ -0,0 +1,52 @@
+package com.thealgorithms.maths;
+
+import com.thealgorithms.maths.Prime.PrimeCheck;
+
+/**
+ * In number theory, a smith number is a composite number for which, in a given number base,
+ * the sum of its digits is equal to the sum of the digits in its prime factorization in the same base.
+ *
+ * For example, in base 10, 378 = 21 X 33 X 71 is a Smith number since 3 + 7 + 8 = 2 X 1 + 3 X 3 + 7 X 1,
+ * and 22 = 21 X 111 is a Smith number, because 2 + 2 = 2 X 1 + (1 + 1) X 1.
+ *
+ * Wiki: https://en.wikipedia.org/wiki/Smith_number
+ */
+public final class SmithNumber {
+
+ private SmithNumber() {
+ }
+
+ private static int primeFactorDigitSum(int n) {
+ int sum = 0;
+ int num = n;
+
+ // Factorize the number using trial division
+ for (int i = 2; i * i <= num; i++) {
+ while (n % i == 0) { // while i divides n
+ sum += SumOfDigits.sumOfDigits(i); // add sum of digits of factor
+ n /= i; // divide n by the factor
+ }
+ }
+
+ // If n is still > 1, it itself is a prime factor
+ if (n > 1) {
+ sum += SumOfDigits.sumOfDigits(n);
+ }
+
+ return sum;
+ }
+
+ /**
+ * Check if {@code number} is Smith number or not
+ *
+ * @param number the number
+ * @return {@code true} if {@code number} is a Smith number, otherwise false
+ */
+ public static boolean isSmithNumber(int number) {
+ if (PrimeCheck.isPrime(number)) {
+ return false; // Smith numbers must be composite
+ }
+
+ return SumOfDigits.sumOfDigits(number) == primeFactorDigitSum(number);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/maths/SmithNumberTest.java b/src/test/java/com/thealgorithms/maths/SmithNumberTest.java
new file mode 100644
index 000000000000..4e2ba0b88e33
--- /dev/null
+++ b/src/test/java/com/thealgorithms/maths/SmithNumberTest.java
@@ -0,0 +1,22 @@
+package com.thealgorithms.maths;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+class SmithNumberTest {
+
+ @ParameterizedTest
+ @CsvSource({"4", "22", "121", "562", "985", "4937775"})
+ void positiveSmithNumbersTest(int n) {
+ assertTrue(SmithNumber.isSmithNumber(n));
+ }
+
+ @ParameterizedTest
+ @CsvSource({"2", "11", "100", "550", "999", "1234557"})
+ void negativeSmithNumbersTest(int n) {
+ assertFalse(SmithNumber.isSmithNumber(n));
+ }
+}
From 3979e824b7683c5435df1b8d703433123da9a31c Mon Sep 17 00:00:00 2001
From: Krishna
Date: Sat, 15 Nov 2025 23:06:01 +0530
Subject: [PATCH 164/272] Add Power of Four Check using bit manipulation
(#7065)
* Add Power of Four Check using bit manipulation
- Implements isPowerOfFour method using bit manipulation
- Checks if number is power of two and has bit at even position
- Includes comprehensive unit tests
- Fixes #6940
* Fix code formatting in PowerOfFourTest
* Move PowerOfFour classes to maths package
* Fix package declaration in PowerOfFourTest
* Fix code formatting in PowerOfFourTest
* Remove redundant import from PowerOfFourTest
* Remove unrelated file
---
.../com/thealgorithms/maths/PowerOfFour.java | 36 +++++++++++++++++++
.../thealgorithms/maths/PowerOfFourTest.java | 36 +++++++++++++++++++
2 files changed, 72 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/maths/PowerOfFour.java
create mode 100644 src/test/java/com/thealgorithms/maths/PowerOfFourTest.java
diff --git a/src/main/java/com/thealgorithms/maths/PowerOfFour.java b/src/main/java/com/thealgorithms/maths/PowerOfFour.java
new file mode 100644
index 000000000000..e5fe6255821b
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/PowerOfFour.java
@@ -0,0 +1,36 @@
+package com.thealgorithms.maths;
+
+/**
+ * Utility class for checking if a number is a power of four.
+ * A power of four is a number that can be expressed as 4^n where n is a non-negative integer.
+ * This class provides a method to determine if a given integer is a power of four using bit manipulation.
+ *
+ * @author krishna-medapati (https://github.com/krishna-medapati)
+ */
+public final class PowerOfFour {
+ private PowerOfFour() {
+ }
+
+ /**
+ * Checks if the given integer is a power of four.
+ *
+ * A number is considered a power of four if:
+ * 1. It is greater than zero
+ * 2. It has exactly one '1' bit in its binary representation (power of two)
+ * 3. The '1' bit is at an even position (0, 2, 4, 6, ...)
+ *
+ * The method uses the mask 0x55555555 (binary: 01010101010101010101010101010101)
+ * to check if the set bit is at an even position.
+ *
+ * @param number the integer to check
+ * @return true if the number is a power of four, false otherwise
+ */
+ public static boolean isPowerOfFour(int number) {
+ if (number <= 0) {
+ return false;
+ }
+ boolean isPowerOfTwo = (number & (number - 1)) == 0;
+ boolean hasEvenBitPosition = (number & 0x55555555) != 0;
+ return isPowerOfTwo && hasEvenBitPosition;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/maths/PowerOfFourTest.java b/src/test/java/com/thealgorithms/maths/PowerOfFourTest.java
new file mode 100644
index 000000000000..c91f8b3cf1b5
--- /dev/null
+++ b/src/test/java/com/thealgorithms/maths/PowerOfFourTest.java
@@ -0,0 +1,36 @@
+package com.thealgorithms.maths;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+class PowerOfFourTest {
+
+ @Test
+ void testPowersOfFour() {
+ assertTrue(PowerOfFour.isPowerOfFour(1));
+ assertTrue(PowerOfFour.isPowerOfFour(4));
+ assertTrue(PowerOfFour.isPowerOfFour(16));
+ assertTrue(PowerOfFour.isPowerOfFour(64));
+ assertTrue(PowerOfFour.isPowerOfFour(256));
+ assertTrue(PowerOfFour.isPowerOfFour(1024));
+ }
+
+ @Test
+ void testNonPowersOfFour() {
+ assertFalse(PowerOfFour.isPowerOfFour(2));
+ assertFalse(PowerOfFour.isPowerOfFour(3));
+ assertFalse(PowerOfFour.isPowerOfFour(5));
+ assertFalse(PowerOfFour.isPowerOfFour(8));
+ assertFalse(PowerOfFour.isPowerOfFour(15));
+ assertFalse(PowerOfFour.isPowerOfFour(32));
+ }
+
+ @Test
+ void testEdgeCases() {
+ assertFalse(PowerOfFour.isPowerOfFour(0));
+ assertFalse(PowerOfFour.isPowerOfFour(-1));
+ assertFalse(PowerOfFour.isPowerOfFour(-4));
+ }
+}
From 93811614b868b2d8f4e1aaa3f4918982036684ff Mon Sep 17 00:00:00 2001
From: GOPISETTI NAVADEEP <2400030007@kluniversity.in>
Date: Sun, 16 Nov 2025 17:24:43 +0530
Subject: [PATCH 165/272] feat: add Count Set Bits algorithm (#7072)
* feat: add Count Set Bits algorithm (issue #6931)
* fix: correct CountSetBits algorithm logic
* style: apply clang-format to CountSetBits files
* fix: correct test expectations for CountSetBits
* fix: correct test expectations for CountSetBits
---
.../bitmanipulation/CountSetBits.java | 114 +++++++++---------
.../bitmanipulation/CountSetBitsTest.java | 56 +++++++--
2 files changed, 100 insertions(+), 70 deletions(-)
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java b/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java
index 242f35fc35f2..7df522ca8f69 100644
--- a/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java
+++ b/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java
@@ -1,79 +1,79 @@
package com.thealgorithms.bitmanipulation;
-public class CountSetBits {
+/**
+ * Utility class to count total set bits from 1 to N
+ * A set bit is a bit in binary representation that is 1
+ *
+ * @author navadeep
+ */
+public final class CountSetBits {
+
+ private CountSetBits() {
+ // Utility class, prevent instantiation
+ }
/**
- * The below algorithm is called as Brian Kernighan's algorithm
- * We can use Brian Kernighan’s algorithm to improve the above naive algorithm’s performance.
- The idea is to only consider the set bits of an integer by turning off its rightmost set bit
- (after counting it), so the next iteration of the loop considers the next rightmost bit.
-
- The expression n & (n-1) can be used to turn off the rightmost set bit of a number n. This
- works as the expression n-1 flips all the bits after the rightmost set bit of n, including the
- rightmost set bit itself. Therefore, n & (n-1) results in the last bit flipped of n.
-
- For example, consider number 52, which is 00110100 in binary, and has a total 3 bits set.
-
- 1st iteration of the loop: n = 52
-
- 00110100 & (n)
- 00110011 (n-1)
- ~~~~~~~~
- 00110000
+ * Counts total number of set bits in all numbers from 1 to n
+ * Time Complexity: O(log n)
+ *
+ * @param n the upper limit (inclusive)
+ * @return total count of set bits from 1 to n
+ * @throws IllegalArgumentException if n is negative
+ */
+ public static int countSetBits(int n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("Input must be non-negative");
+ }
+ if (n == 0) {
+ return 0;
+ }
- 2nd iteration of the loop: n = 48
+ // Find the largest power of 2 <= n
+ int x = largestPowerOf2InNumber(n);
- 00110000 & (n)
- 00101111 (n-1)
- ~~~~~~~~
- 00100000
+ // Total bits at position x: x * 2^(x-1)
+ int bitsAtPositionX = x * (1 << (x - 1));
+ // Remaining numbers after 2^x
+ int remainingNumbers = n - (1 << x) + 1;
- 3rd iteration of the loop: n = 32
+ // Recursively count for the rest
+ int rest = countSetBits(n - (1 << x));
- 00100000 & (n)
- 00011111 (n-1)
- ~~~~~~~~
- 00000000 (n = 0)
+ return bitsAtPositionX + remainingNumbers + rest;
+ }
- * @param num takes Long number whose number of set bit is to be found
- * @return the count of set bits in the binary equivalent
- */
- public long countSetBits(long num) {
- long cnt = 0;
- while (num > 0) {
- cnt++;
- num &= (num - 1);
+ /**
+ * Finds the position of the most significant bit in n
+ *
+ * @param n the number
+ * @return position of MSB (0-indexed from right)
+ */
+ private static int largestPowerOf2InNumber(int n) {
+ int position = 0;
+ while ((1 << position) <= n) {
+ position++;
}
- return cnt;
+ return position - 1;
}
/**
- * This approach takes O(1) running time to count the set bits, but requires a pre-processing.
+ * Alternative naive approach - counts set bits by iterating through all numbers
+ * Time Complexity: O(n log n)
*
- * So, we divide our 32-bit input into 8-bit chunks, with four chunks. We have 8 bits in each chunk.
- *
- * Then the range is from 0-255 (0 to 2^7).
- * So, we may need to count set bits from 0 to 255 in individual chunks.
- *
- * @param num takes a long number
- * @return the count of set bits in the binary equivalent
+ * @param n the upper limit (inclusive)
+ * @return total count of set bits from 1 to n
*/
- public int lookupApproach(int num) {
- int[] table = new int[256];
- table[0] = 0;
-
- for (int i = 1; i < 256; i++) {
- table[i] = (i & 1) + table[i >> 1]; // i >> 1 equals to i/2
+ public static int countSetBitsNaive(int n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("Input must be non-negative");
}
- int res = 0;
- for (int i = 0; i < 4; i++) {
- res += table[num & 0xff];
- num >>= 8;
+ int count = 0;
+ for (int i = 1; i <= n; i++) {
+ count += Integer.bitCount(i);
}
-
- return res;
+ return count;
}
}
diff --git a/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java b/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java
index 61e0757f9c12..757c6edc0151 100644
--- a/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java
+++ b/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java
@@ -1,26 +1,56 @@
package com.thealgorithms.bitmanipulation;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
-public class CountSetBitsTest {
+class CountSetBitsTest {
@Test
- void testSetBits() {
- CountSetBits csb = new CountSetBits();
- assertEquals(1L, csb.countSetBits(16));
- assertEquals(4, csb.countSetBits(15));
- assertEquals(5, csb.countSetBits(10000));
- assertEquals(5, csb.countSetBits(31));
+ void testCountSetBitsZero() {
+ assertEquals(0, CountSetBits.countSetBits(0));
}
@Test
- void testSetBitsLookupApproach() {
- CountSetBits csb = new CountSetBits();
- assertEquals(1L, csb.lookupApproach(16));
- assertEquals(4, csb.lookupApproach(15));
- assertEquals(5, csb.lookupApproach(10000));
- assertEquals(5, csb.lookupApproach(31));
+ void testCountSetBitsOne() {
+ assertEquals(1, CountSetBits.countSetBits(1));
+ }
+
+ @Test
+ void testCountSetBitsSmallNumber() {
+ assertEquals(4, CountSetBits.countSetBits(3)); // 1(1) + 10(1) + 11(2) = 4
+ }
+
+ @Test
+ void testCountSetBitsFive() {
+ assertEquals(7, CountSetBits.countSetBits(5)); // 1 + 1 + 2 + 1 + 2 = 7
+ }
+
+ @Test
+ void testCountSetBitsTen() {
+ assertEquals(17, CountSetBits.countSetBits(10));
+ }
+
+ @Test
+ void testCountSetBitsLargeNumber() {
+ assertEquals(42, CountSetBits.countSetBits(20)); // Changed from 93 to 42
+ }
+
+ @Test
+ void testCountSetBitsPowerOfTwo() {
+ assertEquals(13, CountSetBits.countSetBits(8)); // Changed from 9 to 13
+ }
+
+ @Test
+ void testCountSetBitsNegativeInput() {
+ assertThrows(IllegalArgumentException.class, () -> CountSetBits.countSetBits(-1));
+ }
+
+ @Test
+ void testNaiveApproachMatchesOptimized() {
+ for (int i = 0; i <= 100; i++) {
+ assertEquals(CountSetBits.countSetBitsNaive(i), CountSetBits.countSetBits(i), "Mismatch at n = " + i);
+ }
}
}
From c6880c195d778b1d19fc13d4be1ae09dc355de2f Mon Sep 17 00:00:00 2001
From: GOPISETTI NAVADEEP <2400030007@kluniversity.in>
Date: Sun, 16 Nov 2025 17:30:21 +0530
Subject: [PATCH 166/272] feat: add Sieve of Eratosthenes algorithm (#7071)
* feat: add Sieve of Eratosthenes algorithm
- Implement Sieve of Eratosthenes for finding prime numbers up to n
- Add comprehensive unit tests with edge cases
- Include JavaDoc documentation
- Time complexity: O(n log log n)
- Space complexity: O(n)
Resolves #6939
* fix: remove trailing spaces
* fix: apply clang-format
---
.../maths/SieveOfEratosthenes.java | 98 +++++++++++--------
.../maths/SieveOfEratosthenesTest.java | 60 ++++++++----
2 files changed, 96 insertions(+), 62 deletions(-)
diff --git a/src/main/java/com/thealgorithms/maths/SieveOfEratosthenes.java b/src/main/java/com/thealgorithms/maths/SieveOfEratosthenes.java
index f22d22e8c6af..5a15c4201a15 100644
--- a/src/main/java/com/thealgorithms/maths/SieveOfEratosthenes.java
+++ b/src/main/java/com/thealgorithms/maths/SieveOfEratosthenes.java
@@ -1,66 +1,82 @@
package com.thealgorithms.maths;
-import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
/**
- * @brief utility class implementing Sieve of Eratosthenes
+ * Sieve of Eratosthenes Algorithm
+ * An efficient algorithm to find all prime numbers up to a given limit.
+ *
+ * Algorithm:
+ * 1. Create a boolean array of size n+1, initially all true
+ * 2. Mark 0 and 1 as not prime
+ * 3. For each number i from 2 to sqrt(n):
+ * - If i is still marked as prime
+ * - Mark all multiples of i (starting from i²) as not prime
+ * 4. Collect all numbers still marked as prime
+ *
+ * Time Complexity: O(n log log n)
+ * Space Complexity: O(n)
+ *
+ * @author Navadeep0007
+ * @see Sieve of Eratosthenes
*/
public final class SieveOfEratosthenes {
+
private SieveOfEratosthenes() {
+ // Utility class, prevent instantiation
}
- private static void checkInput(int n) {
- if (n <= 0) {
- throw new IllegalArgumentException("n must be positive.");
+ /**
+ * Finds all prime numbers up to n using the Sieve of Eratosthenes algorithm
+ *
+ * @param n the upper limit (inclusive)
+ * @return a list of all prime numbers from 2 to n
+ * @throws IllegalArgumentException if n is negative
+ */
+ public static List findPrimes(int n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("Input must be non-negative");
}
- }
- private static Type[] sievePrimesTill(int n) {
- checkInput(n);
- Type[] isPrimeArray = new Type[n + 1];
- Arrays.fill(isPrimeArray, Type.PRIME);
- isPrimeArray[0] = Type.NOT_PRIME;
- isPrimeArray[1] = Type.NOT_PRIME;
+ if (n < 2) {
+ return new ArrayList<>();
+ }
+
+ // Create boolean array, initially all true
+ boolean[] isPrime = new boolean[n + 1];
+ for (int i = 2; i <= n; i++) {
+ isPrime[i] = true;
+ }
- double cap = Math.sqrt(n);
- for (int i = 2; i <= cap; i++) {
- if (isPrimeArray[i] == Type.PRIME) {
- for (int j = 2; i * j <= n; j++) {
- isPrimeArray[i * j] = Type.NOT_PRIME;
+ // Sieve process
+ for (int i = 2; i * i <= n; i++) {
+ if (isPrime[i]) {
+ // Mark all multiples of i as not prime
+ for (int j = i * i; j <= n; j += i) {
+ isPrime[j] = false;
}
}
}
- return isPrimeArray;
- }
-
- private static int countPrimes(Type[] isPrimeArray) {
- return (int) Arrays.stream(isPrimeArray).filter(element -> element == Type.PRIME).count();
- }
- private static int[] extractPrimes(Type[] isPrimeArray) {
- int numberOfPrimes = countPrimes(isPrimeArray);
- int[] primes = new int[numberOfPrimes];
- int primeIndex = 0;
- for (int curNumber = 0; curNumber < isPrimeArray.length; ++curNumber) {
- if (isPrimeArray[curNumber] == Type.PRIME) {
- primes[primeIndex++] = curNumber;
+ // Collect all prime numbers
+ List primes = new ArrayList<>();
+ for (int i = 2; i <= n; i++) {
+ if (isPrime[i]) {
+ primes.add(i);
}
}
+
return primes;
}
/**
- * @brief finds all of the prime numbers up to the given upper (inclusive) limit
- * @param n upper (inclusive) limit
- * @exception IllegalArgumentException n is non-positive
- * @return the array of all primes up to the given number (inclusive)
+ * Counts the number of prime numbers up to n
+ *
+ * @param n the upper limit (inclusive)
+ * @return count of prime numbers from 2 to n
*/
- public static int[] findPrimesTill(int n) {
- return extractPrimes(sievePrimesTill(n));
- }
-
- private enum Type {
- PRIME,
- NOT_PRIME,
+ public static int countPrimes(int n) {
+ return findPrimes(n).size();
}
}
diff --git a/src/test/java/com/thealgorithms/maths/SieveOfEratosthenesTest.java b/src/test/java/com/thealgorithms/maths/SieveOfEratosthenesTest.java
index ebbd5df712fc..5d491a493ee7 100644
--- a/src/test/java/com/thealgorithms/maths/SieveOfEratosthenesTest.java
+++ b/src/test/java/com/thealgorithms/maths/SieveOfEratosthenesTest.java
@@ -1,46 +1,64 @@
package com.thealgorithms.maths;
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.util.Arrays;
+import java.util.List;
import org.junit.jupiter.api.Test;
+/**
+ * Test cases for Sieve of Eratosthenes algorithm
+ *
+ * @author Navadeep0007
+ */
class SieveOfEratosthenesTest {
+
+ @Test
+ void testPrimesUpTo10() {
+ List expected = Arrays.asList(2, 3, 5, 7);
+ assertEquals(expected, SieveOfEratosthenes.findPrimes(10));
+ }
+
+ @Test
+ void testPrimesUpTo30() {
+ List expected = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);
+ assertEquals(expected, SieveOfEratosthenes.findPrimes(30));
+ }
+
@Test
- public void testfFindPrimesTill1() {
- assertArrayEquals(new int[] {}, SieveOfEratosthenes.findPrimesTill(1));
+ void testPrimesUpTo2() {
+ List expected = Arrays.asList(2);
+ assertEquals(expected, SieveOfEratosthenes.findPrimes(2));
}
@Test
- public void testfFindPrimesTill2() {
- assertArrayEquals(new int[] {2}, SieveOfEratosthenes.findPrimesTill(2));
+ void testPrimesUpTo1() {
+ assertTrue(SieveOfEratosthenes.findPrimes(1).isEmpty());
}
@Test
- public void testfFindPrimesTill4() {
- var primesTill4 = new int[] {2, 3};
- assertArrayEquals(primesTill4, SieveOfEratosthenes.findPrimesTill(3));
- assertArrayEquals(primesTill4, SieveOfEratosthenes.findPrimesTill(4));
+ void testPrimesUpTo0() {
+ assertTrue(SieveOfEratosthenes.findPrimes(0).isEmpty());
}
@Test
- public void testfFindPrimesTill40() {
- var primesTill40 = new int[] {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
- assertArrayEquals(primesTill40, SieveOfEratosthenes.findPrimesTill(37));
- assertArrayEquals(primesTill40, SieveOfEratosthenes.findPrimesTill(38));
- assertArrayEquals(primesTill40, SieveOfEratosthenes.findPrimesTill(39));
- assertArrayEquals(primesTill40, SieveOfEratosthenes.findPrimesTill(40));
+ void testNegativeInput() {
+ assertThrows(IllegalArgumentException.class, () -> { SieveOfEratosthenes.findPrimes(-1); });
}
@Test
- public void testfFindPrimesTill240() {
- var primesTill240 = new int[] {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239};
- assertArrayEquals(primesTill240, SieveOfEratosthenes.findPrimesTill(239));
- assertArrayEquals(primesTill240, SieveOfEratosthenes.findPrimesTill(240));
+ void testCountPrimes() {
+ assertEquals(4, SieveOfEratosthenes.countPrimes(10));
+ assertEquals(25, SieveOfEratosthenes.countPrimes(100));
}
@Test
- public void testFindPrimesTillThrowsExceptionForNonPositiveInput() {
- assertThrows(IllegalArgumentException.class, () -> SieveOfEratosthenes.findPrimesTill(0));
+ void testLargeNumber() {
+ List primes = SieveOfEratosthenes.findPrimes(1000);
+ assertEquals(168, primes.size()); // There are 168 primes up to 1000
+ assertEquals(2, primes.get(0)); // First prime
+ assertEquals(997, primes.get(primes.size() - 1)); // Last prime up to 1000
}
}
From cff5d3662e5446ff3371adcb5278ccb2085c956f Mon Sep 17 00:00:00 2001
From: SeungHyeok Yun <162292720+SeungHyeokYoon@users.noreply.github.com>
Date: Mon, 17 Nov 2025 03:49:30 +0900
Subject: [PATCH 167/272] feat: add IndexedPriorityQueue implementation and
tests (#7062)
* feat: add IndexedPriorityQueue implementation and tests
* mod : clang-format
* Fix Checkstyle naming for IndexedPriorityQueue tests
* Align IndexedPriorityQueue tests with Checkstyle and clang-format
---
.../heaps/IndexedPriorityQueue.java | 327 ++++++++++++++++
.../heaps/IndexedPriorityQueueTest.java | 350 ++++++++++++++++++
2 files changed, 677 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueue.java
create mode 100644 src/test/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueueTest.java
diff --git a/src/main/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueue.java b/src/main/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueue.java
new file mode 100644
index 000000000000..ad7229760fd0
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueue.java
@@ -0,0 +1,327 @@
+package com.thealgorithms.datastructures.heaps;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.IdentityHashMap;
+import java.util.Objects;
+import java.util.function.Consumer;
+
+/**
+ * An addressable (indexed) min-priority queue with O(log n) updates.
+ *
+ * Key features:
+ *
+ * - Each element E is tracked by a handle (its current heap index) via a map,
+ * enabling O(log n) {@code remove(e)} and O(log n) key updates
+ * ({@code changeKey/decreaseKey/increaseKey}).
+ * - The queue order is determined by the provided {@link Comparator}. If the
+ * comparator is {@code null}, elements must implement {@link Comparable}
+ * (same contract as {@link java.util.PriorityQueue}).
+ * - By default this implementation uses {@link IdentityHashMap} for the index
+ * mapping to avoid issues with duplicate-equals elements or mutable equals/hashCode.
+ * If you need value-based equality, switch to {@code HashMap} and read the caveats
+ * in the class-level Javadoc carefully.
+ *
+ *
+ * IMPORTANT contracts
+ *
+ * - Do not mutate comparator-relevant fields of an element directly while it is
+ * inside the queue. Always use {@code changeKey}/{@code decreaseKey}/{@code increaseKey}
+ * so the heap can be restored accordingly.
+ * - If you replace {@link IdentityHashMap} with {@link HashMap}, you must ensure:
+ * (a) no two distinct elements are {@code equals()}-equal at the same time in the queue, and
+ * (b) {@code equals/hashCode} of elements remain stable while enqueued.
+ * - {@code peek()} returns {@code null} when empty (matching {@link java.util.PriorityQueue}).
+ * - Not thread-safe.
+ *
+ *
+ * Complexities:
+ * {@code offer, poll, remove(e), changeKey, decreaseKey, increaseKey} are O(log n);
+ * {@code peek, isEmpty, size, contains} are O(1).
+ */
+public class IndexedPriorityQueue {
+
+ /** Binary heap storage (min-heap). */
+ private Object[] heap;
+
+ /** Number of elements in the heap. */
+ private int size;
+
+ /** Comparator used for ordering; if null, elements must be Comparable. */
+ private final Comparator super E> cmp;
+
+ /**
+ * Index map: element -> current heap index.
+ * We use IdentityHashMap by default to:
+ *
+ * - allow duplicate-equals elements;
+ * - avoid corruption when equals/hashCode are mutable or not ID-based.
+ *
+ * If you prefer value-based semantics, replace with HashMap and
+ * respect the warnings in the class Javadoc.
+ */
+ private final IdentityHashMap index;
+
+ private static final int DEFAULT_INITIAL_CAPACITY = 11;
+
+ public IndexedPriorityQueue() {
+ this(DEFAULT_INITIAL_CAPACITY, null);
+ }
+
+ public IndexedPriorityQueue(Comparator super E> cmp) {
+ this(DEFAULT_INITIAL_CAPACITY, cmp);
+ }
+
+ public IndexedPriorityQueue(int initialCapacity, Comparator super E> cmp) {
+ if (initialCapacity < 1) {
+ throw new IllegalArgumentException("initialCapacity < 1");
+ }
+ this.heap = new Object[initialCapacity];
+ this.cmp = cmp;
+ this.index = new IdentityHashMap<>();
+ }
+
+ /** Returns current number of elements. */
+ public int size() {
+ return size;
+ }
+
+ /** Returns {@code true} if empty. */
+ public boolean isEmpty() {
+ return size == 0;
+ }
+
+ /**
+ * Returns the minimum element without removing it, or {@code null} if empty.
+ * Matches {@link java.util.PriorityQueue#peek()} behavior.
+ */
+ @SuppressWarnings("unchecked")
+ public E peek() {
+ return size == 0 ? null : (E) heap[0];
+ }
+
+ /**
+ * Inserts the specified element (O(log n)).
+ * @throws NullPointerException if {@code e} is null
+ * @throws ClassCastException if {@code cmp == null} and {@code e} is not Comparable,
+ * or if incompatible with other elements
+ */
+ public boolean offer(E e) {
+ Objects.requireNonNull(e, "element is null");
+ if (size >= heap.length) {
+ grow(size + 1);
+ }
+ // Insert at the end and bubble up. siftUp will maintain 'index' for all touched nodes.
+ siftUp(size, e);
+ size++;
+ return true;
+ }
+
+ /**
+ * Removes and returns the minimum element (O(log n)), or {@code null} if empty.
+ */
+ @SuppressWarnings("unchecked")
+ public E poll() {
+ if (size == 0) {
+ return null;
+ }
+ E min = (E) heap[0];
+ removeAt(0); // updates map and heap structure
+ return min;
+ }
+
+ /**
+ * Removes one occurrence of the specified element e (O(log n)) if present.
+ * Uses the index map for O(1) lookup.
+ */
+ public boolean remove(Object o) {
+ Integer i = index.get(o);
+ if (i == null) {
+ return false;
+ }
+ removeAt(i);
+ return true;
+ }
+
+ /** O(1): returns whether the queue currently contains the given element reference. */
+ public boolean contains(Object o) {
+ return index.containsKey(o);
+ }
+
+ /** Clears the heap and the index map. */
+ public void clear() {
+ Arrays.fill(heap, 0, size, null);
+ index.clear();
+ size = 0;
+ }
+
+ // ------------------------------------------------------------------------------------
+ // Key update API
+ // ------------------------------------------------------------------------------------
+
+ /**
+ * Changes comparator-relevant fields of {@code e} via the provided {@code mutator},
+ * then restores the heap in O(log n) by bubbling in the correct direction.
+ *
+ * IMPORTANT: The mutator must not change {@code equals/hashCode} of {@code e}
+ * if you migrate this implementation to value-based indexing (HashMap).
+ *
+ * @throws IllegalArgumentException if {@code e} is not in the queue
+ */
+ public void changeKey(E e, Consumer mutator) {
+ Integer i = index.get(e);
+ if (i == null) {
+ throw new IllegalArgumentException("Element not in queue");
+ }
+ // Mutate fields used by comparator (do NOT mutate equality/hash if using value-based map)
+ mutator.accept(e);
+ // Try bubbling up; if no movement occurred, bubble down.
+ if (!siftUp(i)) {
+ siftDown(i);
+ }
+ }
+
+ /**
+ * Faster variant if the new key is strictly smaller (higher priority).
+ * Performs a single sift-up (O(log n)).
+ */
+ public void decreaseKey(E e, Consumer mutator) {
+ Integer i = index.get(e);
+ if (i == null) {
+ throw new IllegalArgumentException("Element not in queue");
+ }
+ mutator.accept(e);
+ siftUp(i);
+ }
+
+ /**
+ * Faster variant if the new key is strictly larger (lower priority).
+ * Performs a single sift-down (O(log n)).
+ */
+ public void increaseKey(E e, Consumer mutator) {
+ Integer i = index.get(e);
+ if (i == null) {
+ throw new IllegalArgumentException("Element not in queue");
+ }
+ mutator.accept(e);
+ siftDown(i);
+ }
+
+ // ------------------------------------------------------------------------------------
+ // Internal utilities
+ // ------------------------------------------------------------------------------------
+
+ /** Grows the internal array to accommodate at least {@code minCapacity}. */
+ private void grow(int minCapacity) {
+ int old = heap.length;
+ int pref = (old < 64) ? old + 2 : old + (old >> 1); // +2 if small, else +50%
+ int newCap = Math.max(minCapacity, pref);
+ heap = Arrays.copyOf(heap, newCap);
+ }
+
+ @SuppressWarnings("unchecked")
+ private int compare(E a, E b) {
+ if (cmp != null) {
+ return cmp.compare(a, b);
+ }
+ return ((Comparable super E>) a).compareTo(b);
+ }
+
+ /**
+ * Inserts item {@code x} at position {@code k}, bubbling up while maintaining the heap.
+ * Also maintains the index map for all moved elements.
+ */
+ @SuppressWarnings("unchecked")
+ private void siftUp(int k, E x) {
+ while (k > 0) {
+ int p = (k - 1) >>> 1;
+ E e = (E) heap[p];
+ if (compare(x, e) >= 0) {
+ break;
+ }
+ heap[k] = e;
+ index.put(e, k);
+ k = p;
+ }
+ heap[k] = x;
+ index.put(x, k);
+ }
+
+ /**
+ * Attempts to bubble up the element currently at {@code k}.
+ * @return true if it moved; false otherwise.
+ */
+ @SuppressWarnings("unchecked")
+ private boolean siftUp(int k) {
+ int orig = k;
+ E x = (E) heap[k];
+ while (k > 0) {
+ int p = (k - 1) >>> 1;
+ E e = (E) heap[p];
+ if (compare(x, e) >= 0) {
+ break;
+ }
+ heap[k] = e;
+ index.put(e, k);
+ k = p;
+ }
+ if (k != orig) {
+ heap[k] = x;
+ index.put(x, k);
+ return true;
+ }
+ return false;
+ }
+
+ /** Bubbles down the element currently at {@code k}. */
+ @SuppressWarnings("unchecked")
+ private void siftDown(int k) {
+ int n = size;
+ E x = (E) heap[k];
+ int half = n >>> 1; // loop while k has at least one child
+ while (k < half) {
+ int child = (k << 1) + 1; // assume left is smaller
+ E c = (E) heap[child];
+ int r = child + 1;
+ if (r < n && compare(c, (E) heap[r]) > 0) {
+ child = r;
+ c = (E) heap[child];
+ }
+ if (compare(x, c) <= 0) {
+ break;
+ }
+ heap[k] = c;
+ index.put(c, k);
+ k = child;
+ }
+ heap[k] = x;
+ index.put(x, k);
+ }
+
+ /**
+ * Removes the element at heap index {@code i}, restoring the heap afterwards.
+ * Returns nothing; the standard {@code PriorityQueue} returns a displaced
+ * element in a rare case to help its iterator. We don't need that here, so
+ * we keep the API simple.
+ */
+ @SuppressWarnings("unchecked")
+ private void removeAt(int i) {
+ int n = --size; // last index after removal
+ E moved = (E) heap[n];
+ E removed = (E) heap[i];
+ heap[n] = null; // help GC
+ index.remove(removed); // drop mapping for removed element
+
+ if (i == n) {
+ return; // removed last element; done
+ }
+
+ heap[i] = moved;
+ index.put(moved, i);
+
+ // Try sift-up first (cheap if key decreased); if no movement, sift-down.
+ if (!siftUp(i)) {
+ siftDown(i);
+ }
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueueTest.java b/src/test/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueueTest.java
new file mode 100644
index 000000000000..8d8c4e1db6bd
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueueTest.java
@@ -0,0 +1,350 @@
+package com.thealgorithms.datastructures.heaps;
+
+import java.util.Comparator;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for {@link IndexedPriorityQueue}.
+ *
+ * Notes:
+ * - We mainly use a Node class with a mutable "prio" field to test changeKey/decreaseKey/increaseKey.
+ * - The queue is a min-heap, so smaller "prio" means higher priority.
+ * - By default the implementation uses IdentityHashMap so duplicate-equals objects are allowed.
+ */
+public class IndexedPriorityQueueTest {
+
+ // ------------------------
+ // Helpers
+ // ------------------------
+
+ /** Simple payload with mutable priority. */
+ static class Node {
+ final String id;
+ int prio; // lower is better (min-heap)
+
+ Node(String id, int prio) {
+ this.id = id;
+ this.prio = prio;
+ }
+
+ @Override
+ public String toString() {
+ return id + "(" + prio + ")";
+ }
+ }
+
+ /** Same as Node but overrides equals/hashCode to simulate "duplicate-equals" scenario. */
+ static class NodeWithEquals {
+ final String id;
+ int prio;
+
+ NodeWithEquals(String id, int prio) {
+ this.id = id;
+ this.prio = prio;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof NodeWithEquals)) {
+ return false;
+ }
+ NodeWithEquals other = (NodeWithEquals) o;
+ // Intentionally naive equality: equal if priority is equal
+ return this.prio == other.prio;
+ }
+
+ @Override
+ public int hashCode() {
+ return Integer.hashCode(prio);
+ }
+
+ @Override
+ public String toString() {
+ return id + "(" + prio + ")";
+ }
+ }
+
+ private static IndexedPriorityQueue newNodePQ() {
+ return new IndexedPriorityQueue<>(Comparator.comparingInt(n -> n.prio));
+ }
+
+ // ------------------------
+ // Basic operations
+ // ------------------------
+
+ @Test
+ void testOfferPollWithIntegersComparableMode() {
+ // cmp == null -> elements must be Comparable
+ IndexedPriorityQueue pq = new IndexedPriorityQueue<>();
+ Assertions.assertTrue(pq.isEmpty());
+
+ pq.offer(5);
+ pq.offer(1);
+ pq.offer(3);
+
+ Assertions.assertEquals(3, pq.size());
+ Assertions.assertEquals(1, pq.peek());
+ Assertions.assertEquals(1, pq.poll());
+ Assertions.assertEquals(3, pq.poll());
+ Assertions.assertEquals(5, pq.poll());
+ Assertions.assertNull(pq.poll()); // empty -> null
+ Assertions.assertTrue(pq.isEmpty());
+ }
+
+ @Test
+ void testPeekAndIsEmpty() {
+ IndexedPriorityQueue pq = newNodePQ();
+ Assertions.assertTrue(pq.isEmpty());
+ Assertions.assertNull(pq.peek());
+
+ pq.offer(new Node("A", 10));
+ pq.offer(new Node("B", 5));
+ pq.offer(new Node("C", 7));
+
+ Assertions.assertFalse(pq.isEmpty());
+ Assertions.assertEquals("B(5)", pq.peek().toString());
+ }
+
+ @Test
+ void testRemoveSpecificElement() {
+ IndexedPriorityQueue pq = newNodePQ();
+ Node a = new Node("A", 10);
+ Node b = new Node("B", 5);
+ Node c = new Node("C", 7);
+
+ pq.offer(a);
+ pq.offer(b);
+ pq.offer(c);
+
+ // remove by reference (O(log n))
+ Assertions.assertTrue(pq.remove(b));
+ Assertions.assertEquals(2, pq.size());
+ // now min should be C(7)
+ Assertions.assertEquals("C(7)", pq.peek().toString());
+ // removing an element not present -> false
+ Assertions.assertFalse(pq.remove(b));
+ }
+
+ @Test
+ void testContainsAndClear() {
+ IndexedPriorityQueue pq = newNodePQ();
+ Node a = new Node("A", 2);
+ Node b = new Node("B", 3);
+
+ pq.offer(a);
+ pq.offer(b);
+
+ Assertions.assertTrue(pq.contains(a));
+ Assertions.assertTrue(pq.contains(b));
+
+ pq.clear();
+ Assertions.assertTrue(pq.isEmpty());
+ Assertions.assertFalse(pq.contains(a));
+ Assertions.assertNull(pq.peek());
+ }
+
+ // ------------------------
+ // Key updates
+ // ------------------------
+
+ @Test
+ void testDecreaseKeyMovesUp() {
+ IndexedPriorityQueue pq = newNodePQ();
+ Node a = new Node("A", 10);
+ Node b = new Node("B", 5);
+ Node c = new Node("C", 7);
+
+ pq.offer(a);
+ pq.offer(b);
+ pq.offer(c);
+
+ // current min is B(5)
+ Assertions.assertEquals("B(5)", pq.peek().toString());
+
+ // Make A more important: 10 -> 1 (smaller is better)
+ pq.decreaseKey(a, n -> n.prio = 1);
+
+ // Now A should be at the top
+ Assertions.assertEquals("A(1)", pq.peek().toString());
+ }
+
+ @Test
+ void testIncreaseKeyMovesDown() {
+ IndexedPriorityQueue pq = newNodePQ();
+ Node a = new Node("A", 1);
+ Node b = new Node("B", 2);
+ Node c = new Node("C", 3);
+
+ pq.offer(a);
+ pq.offer(b);
+ pq.offer(c);
+
+ // min is A(1)
+ Assertions.assertEquals("A(1)", pq.peek().toString());
+
+ // Make A worse: 1 -> 100
+ pq.increaseKey(a, n -> n.prio = 100);
+
+ // Now min should be B(2)
+ Assertions.assertEquals("B(2)", pq.peek().toString());
+ }
+
+ @Test
+ void testChangeKeyChoosesDirectionAutomatically() {
+ IndexedPriorityQueue pq = newNodePQ();
+ Node a = new Node("A", 10);
+ Node b = new Node("B", 20);
+ Node c = new Node("C", 30);
+
+ pq.offer(a);
+ pq.offer(b);
+ pq.offer(c);
+
+ // Decrease B to 0 -> should move up
+ pq.changeKey(b, n -> n.prio = 0);
+ Assertions.assertEquals("B(0)", pq.peek().toString());
+
+ // Increase B to 100 -> should move down
+ pq.changeKey(b, n -> n.prio = 100);
+ Assertions.assertEquals("A(10)", pq.peek().toString());
+ }
+
+ @Test
+ void testDirectMutationWithoutChangeKeyDoesNotReheapByDesign() {
+ // Demonstrates the contract: do NOT mutate comparator fields directly.
+ IndexedPriorityQueue pq = newNodePQ();
+ Node a = new Node("A", 5);
+ Node b = new Node("B", 10);
+
+ pq.offer(a);
+ pq.offer(b);
+
+ // Illegally mutate priority directly
+ a.prio = 100; // worse than b now, but heap wasn't notified
+
+ // The heap structure is unchanged; peek still returns A(100) (was A(5) before)
+ // This test documents the behavior/contract rather than relying on it.
+ Assertions.assertEquals("A(100)", pq.peek().toString());
+
+ // Now fix properly via changeKey (no change in value, but triggers reheap)
+ pq.changeKey(a, n -> n.prio = n.prio);
+ Assertions.assertEquals("B(10)", pq.peek().toString());
+ }
+
+ // ------------------------
+ // Identity semantics & duplicates
+ // ------------------------
+
+ @Test
+ void testDuplicateEqualsElementsAreSupportedIdentityMap() {
+ IndexedPriorityQueue pq = new IndexedPriorityQueue<>(Comparator.comparingInt(n -> n.prio));
+
+ NodeWithEquals x1 = new NodeWithEquals("X1", 7);
+ NodeWithEquals x2 = new NodeWithEquals("X2", 7); // equals to X1 by prio, but different instance
+
+ // With IdentityHashMap internally, both can coexist
+ pq.offer(x1);
+ pq.offer(x2);
+
+ Assertions.assertEquals(2, pq.size());
+ // Poll twice; both 7s should be returned (order between x1/x2 is unspecified)
+ Assertions.assertEquals(7, pq.poll().prio);
+ Assertions.assertEquals(7, pq.poll().prio);
+ Assertions.assertTrue(pq.isEmpty());
+ }
+
+ // ------------------------
+ // Capacity growth
+ // ------------------------
+
+ @Test
+ void testGrowByManyInserts() {
+ IndexedPriorityQueue pq = new IndexedPriorityQueue<>();
+ int n = 100; // beyond default capacity (11)
+
+ for (int i = n; i >= 1; i--) {
+ pq.offer(i);
+ }
+
+ Assertions.assertEquals(n, pq.size());
+ // Ensure min-to-max order when polling
+ for (int expected = 1; expected <= n; expected++) {
+ Integer v = pq.poll();
+ Assertions.assertEquals(expected, v);
+ }
+ Assertions.assertTrue(pq.isEmpty());
+ Assertions.assertNull(pq.poll());
+ }
+
+ // ------------------------
+ // remove/contains edge cases
+ // ------------------------
+
+ @Test
+ void testRemoveHeadAndMiddleAndTail() {
+ IndexedPriorityQueue pq = newNodePQ();
+ Node a = new Node("A", 1);
+ Node b = new Node("B", 2);
+ Node c = new Node("C", 3);
+ Node d = new Node("D", 4);
+
+ pq.offer(a);
+ pq.offer(b);
+ pq.offer(c);
+ pq.offer(d);
+
+ // remove head
+ Assertions.assertTrue(pq.remove(a));
+ Assertions.assertFalse(pq.contains(a));
+ Assertions.assertEquals("B(2)", pq.peek().toString());
+
+ // remove middle
+ Assertions.assertTrue(pq.remove(c));
+ Assertions.assertFalse(pq.contains(c));
+ Assertions.assertEquals("B(2)", pq.peek().toString());
+
+ // remove tail (last)
+ Assertions.assertTrue(pq.remove(d));
+ Assertions.assertFalse(pq.contains(d));
+ Assertions.assertEquals("B(2)", pq.peek().toString());
+
+ // remove last remaining
+ Assertions.assertTrue(pq.remove(b));
+ Assertions.assertTrue(pq.isEmpty());
+ Assertions.assertNull(pq.peek());
+ }
+
+ // ------------------------
+ // Error / edge cases for coverage
+ // ------------------------
+
+ @Test
+ void testInvalidInitialCapacityThrows() {
+ Assertions.assertThrows(IllegalArgumentException.class, () -> new IndexedPriorityQueue(0, Comparator.naturalOrder()));
+ }
+
+ @Test
+ void testChangeKeyOnMissingElementThrows() {
+ IndexedPriorityQueue pq = newNodePQ();
+ Node a = new Node("A", 10);
+
+ Assertions.assertThrows(IllegalArgumentException.class, () -> pq.changeKey(a, n -> n.prio = 5));
+ }
+
+ @Test
+ void testDecreaseKeyOnMissingElementThrows() {
+ IndexedPriorityQueue pq = newNodePQ();
+ Node a = new Node("A", 10);
+
+ Assertions.assertThrows(IllegalArgumentException.class, () -> pq.decreaseKey(a, n -> n.prio = 5));
+ }
+
+ @Test
+ void testIncreaseKeyOnMissingElementThrows() {
+ IndexedPriorityQueue pq = newNodePQ();
+ Node a = new Node("A", 10);
+
+ Assertions.assertThrows(IllegalArgumentException.class, () -> pq.increaseKey(a, n -> n.prio = 15));
+ }
+}
From 9f2b675f3e47c49bf4d1623d9d04f95506e2f813 Mon Sep 17 00:00:00 2001
From: GOPISETTI NAVADEEP <2400030007@kluniversity.in>
Date: Mon, 17 Nov 2025 14:24:20 +0530
Subject: [PATCH 168/272] feat: add Sudoku Solver using Backtracking (#7073)
* feat: add Sudoku Solver using Backtracking (issue #6929)
* refactor: remove old Sudoku class from puzzlesandgames package
* Remove old Sudoku implementation and its test class
---
.../backtracking/SudokuSolver.java | 157 ++++++++++++++++
.../thealgorithms/puzzlesandgames/Sudoku.java | 169 ------------------
.../backtracking/SudokuSolverTest.java | 53 ++++++
.../puzzlesandgames/SudokuTest.java | 38 ----
4 files changed, 210 insertions(+), 207 deletions(-)
create mode 100644 src/main/java/com/thealgorithms/backtracking/SudokuSolver.java
delete mode 100644 src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java
create mode 100644 src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java
delete mode 100644 src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java
diff --git a/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java b/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java
new file mode 100644
index 000000000000..543fe2d02b50
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java
@@ -0,0 +1,157 @@
+package com.thealgorithms.backtracking;
+
+/**
+ * Sudoku Solver using Backtracking Algorithm
+ * Solves a 9x9 Sudoku puzzle by filling empty cells with valid digits (1-9)
+ *
+ * @author Navadeep0007
+ */
+public final class SudokuSolver {
+
+ private static final int GRID_SIZE = 9;
+ private static final int SUBGRID_SIZE = 3;
+ private static final int EMPTY_CELL = 0;
+
+ private SudokuSolver() {
+ // Utility class, prevent instantiation
+ }
+
+ /**
+ * Solves the Sudoku puzzle using backtracking
+ *
+ * @param board 9x9 Sudoku board with 0 representing empty cells
+ * @return true if puzzle is solved, false otherwise
+ */
+ public static boolean solveSudoku(int[][] board) {
+ if (board == null || board.length != GRID_SIZE) {
+ return false;
+ }
+
+ for (int row = 0; row < GRID_SIZE; row++) {
+ if (board[row].length != GRID_SIZE) {
+ return false;
+ }
+ }
+
+ return solve(board);
+ }
+
+ /**
+ * Recursive helper method to solve the Sudoku puzzle
+ *
+ * @param board the Sudoku board
+ * @return true if solution is found, false otherwise
+ */
+ private static boolean solve(int[][] board) {
+ for (int row = 0; row < GRID_SIZE; row++) {
+ for (int col = 0; col < GRID_SIZE; col++) {
+ if (board[row][col] == EMPTY_CELL) {
+ for (int number = 1; number <= GRID_SIZE; number++) {
+ if (isValidPlacement(board, row, col, number)) {
+ board[row][col] = number;
+
+ if (solve(board)) {
+ return true;
+ }
+
+ // Backtrack
+ board[row][col] = EMPTY_CELL;
+ }
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Checks if placing a number at given position is valid
+ *
+ * @param board the Sudoku board
+ * @param row row index
+ * @param col column index
+ * @param number number to place (1-9)
+ * @return true if placement is valid, false otherwise
+ */
+ private static boolean isValidPlacement(int[][] board, int row, int col, int number) {
+ return !isNumberInRow(board, row, number) && !isNumberInColumn(board, col, number) && !isNumberInSubgrid(board, row, col, number);
+ }
+
+ /**
+ * Checks if number exists in the given row
+ *
+ * @param board the Sudoku board
+ * @param row row index
+ * @param number number to check
+ * @return true if number exists in row, false otherwise
+ */
+ private static boolean isNumberInRow(int[][] board, int row, int number) {
+ for (int col = 0; col < GRID_SIZE; col++) {
+ if (board[row][col] == number) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks if number exists in the given column
+ *
+ * @param board the Sudoku board
+ * @param col column index
+ * @param number number to check
+ * @return true if number exists in column, false otherwise
+ */
+ private static boolean isNumberInColumn(int[][] board, int col, int number) {
+ for (int row = 0; row < GRID_SIZE; row++) {
+ if (board[row][col] == number) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks if number exists in the 3x3 subgrid
+ *
+ * @param board the Sudoku board
+ * @param row row index
+ * @param col column index
+ * @param number number to check
+ * @return true if number exists in subgrid, false otherwise
+ */
+ private static boolean isNumberInSubgrid(int[][] board, int row, int col, int number) {
+ int subgridRowStart = row - row % SUBGRID_SIZE;
+ int subgridColStart = col - col % SUBGRID_SIZE;
+
+ for (int i = subgridRowStart; i < subgridRowStart + SUBGRID_SIZE; i++) {
+ for (int j = subgridColStart; j < subgridColStart + SUBGRID_SIZE; j++) {
+ if (board[i][j] == number) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Prints the Sudoku board
+ *
+ * @param board the Sudoku board
+ */
+ public static void printBoard(int[][] board) {
+ for (int row = 0; row < GRID_SIZE; row++) {
+ if (row % SUBGRID_SIZE == 0 && row != 0) {
+ System.out.println("-----------");
+ }
+ for (int col = 0; col < GRID_SIZE; col++) {
+ if (col % SUBGRID_SIZE == 0 && col != 0) {
+ System.out.print("|");
+ }
+ System.out.print(board[row][col]);
+ }
+ System.out.println();
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java b/src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java
deleted file mode 100644
index fce665c4de00..000000000000
--- a/src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java
+++ /dev/null
@@ -1,169 +0,0 @@
-package com.thealgorithms.puzzlesandgames;
-
-/**
- * A class that provides methods to solve Sudoku puzzles of any n x n size
- * using a backtracking approach, where n must be a perfect square.
- * The algorithm checks for safe number placements in rows, columns,
- * and subgrids (which are sqrt(n) x sqrt(n) in size) and recursively solves the puzzle.
- * Though commonly used for 9x9 grids, it is adaptable to other valid Sudoku dimensions.
- */
-final class Sudoku {
-
- private Sudoku() {
- }
-
- /**
- * Checks if placing a number in a specific position on the Sudoku board is safe.
- * The number is considered safe if it does not violate any of the Sudoku rules:
- * - It should not be present in the same row.
- * - It should not be present in the same column.
- * - It should not be present in the corresponding 3x3 subgrid.
- * - It should not be present in the corresponding subgrid, which is sqrt(n) x sqrt(n) in size (e.g., for a 9x9 grid, the subgrid will be 3x3).
- *
- * @param board The current state of the Sudoku board.
- * @param row The row index where the number is to be placed.
- * @param col The column index where the number is to be placed.
- * @param num The number to be placed on the board.
- * @return True if the placement is safe, otherwise false.
- */
- public static boolean isSafe(int[][] board, int row, int col, int num) {
- // Check the row for duplicates
- for (int d = 0; d < board.length; d++) {
- if (board[row][d] == num) {
- return false;
- }
- }
-
- // Check the column for duplicates
- for (int r = 0; r < board.length; r++) {
- if (board[r][col] == num) {
- return false;
- }
- }
-
- // Check the corresponding 3x3 subgrid for duplicates
- int sqrt = (int) Math.sqrt(board.length);
- int boxRowStart = row - row % sqrt;
- int boxColStart = col - col % sqrt;
-
- for (int r = boxRowStart; r < boxRowStart + sqrt; r++) {
- for (int d = boxColStart; d < boxColStart + sqrt; d++) {
- if (board[r][d] == num) {
- return false;
- }
- }
- }
-
- return true;
- }
-
- /**
- * Solves the Sudoku puzzle using backtracking.
- * The algorithm finds an empty cell and tries placing numbers
- * from 1 to n, where n is the size of the board
- * (for example, from 1 to 9 in a standard 9x9 Sudoku).
- * The algorithm finds an empty cell and tries placing numbers from 1 to 9.
- * The standard version of Sudoku uses numbers from 1 to 9, so the algorithm can be
- * easily modified for other variations of the game.
- * If a number placement is valid (checked via `isSafe`), the number is
- * placed and the function recursively attempts to solve the rest of the puzzle.
- * If no solution is possible, the number is removed (backtracked),
- * and the process is repeated.
- *
- * @param board The current state of the Sudoku board.
- * @param n The size of the Sudoku board (typically 9 for a standard puzzle).
- * @return True if the Sudoku puzzle is solvable, false otherwise.
- */
- public static boolean solveSudoku(int[][] board, int n) {
- int row = -1;
- int col = -1;
- boolean isEmpty = true;
-
- // Find the next empty cell
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < n; j++) {
- if (board[i][j] == 0) {
- row = i;
- col = j;
- isEmpty = false;
- break;
- }
- }
- if (!isEmpty) {
- break;
- }
- }
-
- // No empty space left
- if (isEmpty) {
- return true;
- }
-
- // Try placing numbers 1 to n in the empty cell (n should be a perfect square)
- // Eg: n=9 for a standard 9x9 Sudoku puzzle, n=16 for a 16x16 puzzle, etc.
- for (int num = 1; num <= n; num++) {
- if (isSafe(board, row, col, num)) {
- board[row][col] = num;
- if (solveSudoku(board, n)) {
- return true;
- } else {
- // replace it
- board[row][col] = 0;
- }
- }
- }
- return false;
- }
-
- /**
- * Prints the current state of the Sudoku board in a readable format.
- * Each row is printed on a new line, with numbers separated by spaces.
- *
- * @param board The current state of the Sudoku board.
- * @param n The size of the Sudoku board (typically 9 for a standard puzzle).
- */
- public static void print(int[][] board, int n) {
- // Print the board in a nxn grid format
- // if n=9, print the board in a 9x9 grid format
- // if n=16, print the board in a 16x16 grid format
- for (int r = 0; r < n; r++) {
- for (int d = 0; d < n; d++) {
- System.out.print(board[r][d]);
- System.out.print(" ");
- }
- System.out.print("\n");
-
- if ((r + 1) % (int) Math.sqrt(n) == 0) {
- System.out.print("");
- }
- }
- }
-
- /**
- * The driver method to demonstrate solving a Sudoku puzzle.
- * A sample 9x9 Sudoku puzzle is provided, and the program attempts to solve it
- * using the `solveSudoku` method. If a solution is found, it is printed to the console.
- *
- * @param args Command-line arguments (not used in this program).
- */
- public static void main(String[] args) {
- int[][] board = new int[][] {
- {3, 0, 6, 5, 0, 8, 4, 0, 0},
- {5, 2, 0, 0, 0, 0, 0, 0, 0},
- {0, 8, 7, 0, 0, 0, 0, 3, 1},
- {0, 0, 3, 0, 1, 0, 0, 8, 0},
- {9, 0, 0, 8, 6, 3, 0, 0, 5},
- {0, 5, 0, 0, 9, 0, 6, 0, 0},
- {1, 3, 0, 0, 0, 0, 2, 5, 0},
- {0, 0, 0, 0, 0, 0, 0, 7, 4},
- {0, 0, 5, 2, 0, 6, 3, 0, 0},
- };
- int n = board.length;
-
- if (solveSudoku(board, n)) {
- print(board, n);
- } else {
- System.out.println("No solution");
- }
- }
-}
diff --git a/src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java b/src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java
new file mode 100644
index 000000000000..75d3eae08629
--- /dev/null
+++ b/src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java
@@ -0,0 +1,53 @@
+package com.thealgorithms.backtracking;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+class SudokuSolverTest {
+
+ @Test
+ void testSolveSudokuEasyPuzzle() {
+ int[][] board = {{5, 3, 0, 0, 7, 0, 0, 0, 0}, {6, 0, 0, 1, 9, 5, 0, 0, 0}, {0, 9, 8, 0, 0, 0, 0, 6, 0}, {8, 0, 0, 0, 6, 0, 0, 0, 3}, {4, 0, 0, 8, 0, 3, 0, 0, 1}, {7, 0, 0, 0, 2, 0, 0, 0, 6}, {0, 6, 0, 0, 0, 0, 2, 8, 0}, {0, 0, 0, 4, 1, 9, 0, 0, 5}, {0, 0, 0, 0, 8, 0, 0, 7, 9}};
+
+ assertTrue(SudokuSolver.solveSudoku(board));
+
+ int[][] expected = {{5, 3, 4, 6, 7, 8, 9, 1, 2}, {6, 7, 2, 1, 9, 5, 3, 4, 8}, {1, 9, 8, 3, 4, 2, 5, 6, 7}, {8, 5, 9, 7, 6, 1, 4, 2, 3}, {4, 2, 6, 8, 5, 3, 7, 9, 1}, {7, 1, 3, 9, 2, 4, 8, 5, 6}, {9, 6, 1, 5, 3, 7, 2, 8, 4}, {2, 8, 7, 4, 1, 9, 6, 3, 5}, {3, 4, 5, 2, 8, 6, 1, 7, 9}};
+
+ assertArrayEquals(expected, board);
+ }
+
+ @Test
+ void testSolveSudokuHardPuzzle() {
+ int[][] board = {{0, 0, 0, 0, 0, 0, 6, 8, 0}, {0, 0, 0, 0, 7, 3, 0, 0, 9}, {3, 0, 9, 0, 0, 0, 0, 4, 5}, {4, 9, 0, 0, 0, 0, 0, 0, 0}, {8, 0, 3, 0, 5, 0, 9, 0, 2}, {0, 0, 0, 0, 0, 0, 0, 3, 6}, {9, 6, 0, 0, 0, 0, 3, 0, 8}, {7, 0, 0, 6, 8, 0, 0, 0, 0}, {0, 2, 8, 0, 0, 0, 0, 0, 0}};
+
+ assertTrue(SudokuSolver.solveSudoku(board));
+ }
+
+ @Test
+ void testSolveSudokuAlreadySolved() {
+ int[][] board = {{5, 3, 4, 6, 7, 8, 9, 1, 2}, {6, 7, 2, 1, 9, 5, 3, 4, 8}, {1, 9, 8, 3, 4, 2, 5, 6, 7}, {8, 5, 9, 7, 6, 1, 4, 2, 3}, {4, 2, 6, 8, 5, 3, 7, 9, 1}, {7, 1, 3, 9, 2, 4, 8, 5, 6}, {9, 6, 1, 5, 3, 7, 2, 8, 4}, {2, 8, 7, 4, 1, 9, 6, 3, 5}, {3, 4, 5, 2, 8, 6, 1, 7, 9}};
+
+ assertTrue(SudokuSolver.solveSudoku(board));
+ }
+
+ @Test
+ void testSolveSudokuInvalidSize() {
+ int[][] board = {{1, 2, 3}, {4, 5, 6}};
+ assertFalse(SudokuSolver.solveSudoku(board));
+ }
+
+ @Test
+ void testSolveSudokuNullBoard() {
+ assertFalse(SudokuSolver.solveSudoku(null));
+ }
+
+ @Test
+ void testSolveSudokuEmptyBoard() {
+ int[][] board = {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}};
+
+ assertTrue(SudokuSolver.solveSudoku(board));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java b/src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java
deleted file mode 100644
index 7fb96dcf805f..000000000000
--- a/src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.thealgorithms.puzzlesandgames;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import org.junit.jupiter.api.Test;
-
-public class SudokuTest {
-
- @Test
- void testIsSafe2() {
- int[][] board = {{3, 0, 6, 5, 0, 8, 4, 0, 0}, {5, 2, 0, 0, 0, 0, 0, 0, 0}, {0, 8, 7, 0, 0, 0, 0, 3, 1}, {0, 0, 3, 0, 1, 0, 0, 8, 0}, {9, 0, 0, 8, 6, 3, 0, 0, 5}, {0, 5, 0, 0, 9, 0, 6, 0, 0}, {1, 3, 0, 0, 0, 0, 2, 5, 0}, {0, 0, 0, 0, 0, 0, 0, 7, 4}, {0, 0, 5, 2, 0, 6, 3, 0, 0}};
-
- assertFalse(Sudoku.isSafe(board, 0, 1, 3));
- assertTrue(Sudoku.isSafe(board, 1, 2, 1));
- assertThrows(ArrayIndexOutOfBoundsException.class, () -> { Sudoku.isSafe(board, 10, 10, 5); });
- assertThrows(ArrayIndexOutOfBoundsException.class, () -> { Sudoku.isSafe(board, -1, 0, 5); });
- }
-
- @Test
- void testSolveSudoku() {
- int[][] board = {{3, 0, 6, 5, 0, 8, 4, 0, 0}, {5, 2, 0, 0, 0, 0, 0, 0, 0}, {0, 8, 7, 0, 0, 0, 0, 3, 1}, {0, 0, 3, 0, 1, 0, 0, 8, 0}, {9, 0, 0, 8, 6, 3, 0, 0, 5}, {0, 5, 0, 0, 9, 0, 6, 0, 0}, {1, 3, 0, 0, 0, 0, 2, 5, 0}, {0, 0, 0, 0, 0, 0, 0, 7, 4}, {0, 0, 5, 2, 0, 6, 3, 0, 0}};
-
- assertTrue(Sudoku.solveSudoku(board, board.length));
- assertEquals(1, board[0][1]);
- assertThrows(ArrayIndexOutOfBoundsException.class, () -> { Sudoku.solveSudoku(board, 10); });
- assertTrue(Sudoku.solveSudoku(board, -1));
- }
-
- @Test
- void testUnsolvableSudoku() {
- int[][] unsolvableBoard = {{5, 1, 6, 8, 4, 9, 7, 3, 2}, {3, 0, 7, 6, 0, 5, 0, 0, 0}, {8, 0, 9, 7, 0, 0, 0, 6, 5}, {1, 3, 5, 0, 6, 0, 9, 0, 7}, {4, 7, 2, 5, 9, 1, 0, 0, 6}, {9, 6, 8, 3, 7, 0, 0, 5, 0}, {2, 5, 3, 1, 8, 6, 0, 7, 4}, {6, 8, 4, 2, 5, 7, 3, 9, 0}, {7, 9, 1, 4, 3, 0, 5, 0, 0}};
-
- assertFalse(Sudoku.solveSudoku(unsolvableBoard, unsolvableBoard.length));
- }
-}
From 1c97ad8015855780e7d86248dd2938ef38caf2d4 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 17 Nov 2025 22:16:07 +0100
Subject: [PATCH 169/272] chore(deps): bump org.apache.commons:commons-lang3
from 3.19.0 to 3.20.0 (#7076)
Bumps org.apache.commons:commons-lang3 from 3.19.0 to 3.20.0.
---
updated-dependencies:
- dependency-name: org.apache.commons:commons-lang3
dependency-version: 3.20.0
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 6126bbe4d6c5..774db2ec4403 100644
--- a/pom.xml
+++ b/pom.xml
@@ -48,7 +48,7 @@
org.apache.commons
commons-lang3
- 3.19.0
+ 3.20.0
org.apache.commons
From 3519e396af269683a42796ef653b37abdcd7d791 Mon Sep 17 00:00:00 2001
From: shreeya-g10
Date: Wed, 19 Nov 2025 21:50:46 +0530
Subject: [PATCH 170/272] backtracking: add unique permutation algorithm with
test cases (#7078)
* Add unique permutation algorithm and test cases
* Fix: add braces for checkstyle
* Apply clang-format
---
.../backtracking/UniquePermutation.java | 62 +++++++++++++++++++
.../backtracking/UniquePermutationTest.java | 31 ++++++++++
2 files changed, 93 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/backtracking/UniquePermutation.java
create mode 100644 src/test/java/com/thealgorithms/backtracking/UniquePermutationTest.java
diff --git a/src/main/java/com/thealgorithms/backtracking/UniquePermutation.java b/src/main/java/com/thealgorithms/backtracking/UniquePermutation.java
new file mode 100644
index 000000000000..4804e247ab03
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/UniquePermutation.java
@@ -0,0 +1,62 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Generates all UNIQUE permutations of a string, even when duplicate characters exist.
+ *
+ * Example:
+ * Input: "AAB"
+ * Output: ["AAB", "ABA", "BAA"]
+ *
+ * Time Complexity: O(n! * n)
+ */
+public final class UniquePermutation {
+
+ private UniquePermutation() {
+ // Prevent instantiation
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ public static List generateUniquePermutations(String input) {
+ List result = new ArrayList<>();
+ if (input == null) {
+ return result;
+ }
+
+ char[] chars = input.toCharArray();
+ Arrays.sort(chars); // important: sort to detect duplicates
+
+ backtrack(chars, new boolean[chars.length], new StringBuilder(), result);
+ return result;
+ }
+
+ private static void backtrack(char[] chars, boolean[] used, StringBuilder current, List result) {
+
+ if (current.length() == chars.length) {
+ result.add(current.toString());
+ return;
+ }
+
+ for (int i = 0; i < chars.length; i++) {
+
+ // skip duplicates
+ if (i > 0 && chars[i] == chars[i - 1] && !used[i - 1]) {
+ continue;
+ }
+
+ if (!used[i]) {
+ used[i] = true;
+ current.append(chars[i]);
+
+ backtrack(chars, used, current, result);
+
+ // undo changes
+ used[i] = false;
+ current.deleteCharAt(current.length() - 1);
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/thealgorithms/backtracking/UniquePermutationTest.java b/src/test/java/com/thealgorithms/backtracking/UniquePermutationTest.java
new file mode 100644
index 000000000000..c8e7cd0af0dd
--- /dev/null
+++ b/src/test/java/com/thealgorithms/backtracking/UniquePermutationTest.java
@@ -0,0 +1,31 @@
+package com.thealgorithms.backtracking;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+public class UniquePermutationTest {
+
+ @Test
+ void testUniquePermutationsAab() {
+ List expected = Arrays.asList("AAB", "ABA", "BAA");
+ List result = UniquePermutation.generateUniquePermutations("AAB");
+ assertEquals(expected, result);
+ }
+
+ @Test
+ void testUniquePermutationsAbc() {
+ List expected = Arrays.asList("ABC", "ACB", "BAC", "BCA", "CAB", "CBA");
+ List result = UniquePermutation.generateUniquePermutations("ABC");
+ assertEquals(expected, result);
+ }
+
+ @Test
+ void testEmptyString() {
+ List expected = Arrays.asList("");
+ List result = UniquePermutation.generateUniquePermutations("");
+ assertEquals(expected, result);
+ }
+}
From e37a7ab6ce87c7cf13274366dca536d34cfc5668 Mon Sep 17 00:00:00 2001
From: Deniz Altunkapan
Date: Wed, 19 Nov 2025 17:25:09 +0100
Subject: [PATCH 171/272] Update DIRECTORY.md (#7070)
Co-authored-by: alxkm
---
DIRECTORY.md | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/DIRECTORY.md b/DIRECTORY.md
index f15d65c18c3f..042efa72addc 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -24,6 +24,8 @@
- 📄 [Permutation](src/main/java/com/thealgorithms/backtracking/Permutation.java)
- 📄 [PowerSum](src/main/java/com/thealgorithms/backtracking/PowerSum.java)
- 📄 [SubsequenceFinder](src/main/java/com/thealgorithms/backtracking/SubsequenceFinder.java)
+ - 📄 [SudokuSolver](src/main/java/com/thealgorithms/backtracking/SudokuSolver.java)
+ - 📄 [UniquePermutation](src/main/java/com/thealgorithms/backtracking/UniquePermutation.java)
- 📄 [WordPatternMatcher](src/main/java/com/thealgorithms/backtracking/WordPatternMatcher.java)
- 📄 [WordSearch](src/main/java/com/thealgorithms/backtracking/WordSearch.java)
- 📁 **bitmanipulation**
@@ -133,6 +135,7 @@
- 📄 [PhoneticAlphabetConverter](src/main/java/com/thealgorithms/conversions/PhoneticAlphabetConverter.java)
- 📄 [RgbHsvConversion](src/main/java/com/thealgorithms/conversions/RgbHsvConversion.java)
- 📄 [RomanToInteger](src/main/java/com/thealgorithms/conversions/RomanToInteger.java)
+ - 📄 [TemperatureConverter](src/main/java/com/thealgorithms/conversions/TemperatureConverter.java)
- 📄 [TimeConverter](src/main/java/com/thealgorithms/conversions/TimeConverter.java)
- 📄 [TurkishToLatinConversion](src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java)
- 📄 [UnitConversions](src/main/java/com/thealgorithms/conversions/UnitConversions.java)
@@ -208,6 +211,7 @@
- 📄 [GenericHeap](src/main/java/com/thealgorithms/datastructures/heaps/GenericHeap.java)
- 📄 [Heap](src/main/java/com/thealgorithms/datastructures/heaps/Heap.java)
- 📄 [HeapElement](src/main/java/com/thealgorithms/datastructures/heaps/HeapElement.java)
+ - 📄 [IndexedPriorityQueue](src/main/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueue.java)
- 📄 [KthElementFinder](src/main/java/com/thealgorithms/datastructures/heaps/KthElementFinder.java)
- 📄 [LeftistHeap](src/main/java/com/thealgorithms/datastructures/heaps/LeftistHeap.java)
- 📄 [MaxHeap](src/main/java/com/thealgorithms/datastructures/heaps/MaxHeap.java)
@@ -507,6 +511,7 @@
- 📄 [PiNilakantha](src/main/java/com/thealgorithms/maths/PiNilakantha.java)
- 📄 [PollardRho](src/main/java/com/thealgorithms/maths/PollardRho.java)
- 📄 [Pow](src/main/java/com/thealgorithms/maths/Pow.java)
+ - 📄 [PowerOfFour](src/main/java/com/thealgorithms/maths/PowerOfFour.java)
- 📄 [PowerOfTwoOrNot](src/main/java/com/thealgorithms/maths/PowerOfTwoOrNot.java)
- 📄 [PowerUsingRecursion](src/main/java/com/thealgorithms/maths/PowerUsingRecursion.java)
- 📁 **Prime**
@@ -525,6 +530,7 @@
- 📄 [SieveOfAtkin](src/main/java/com/thealgorithms/maths/SieveOfAtkin.java)
- 📄 [SieveOfEratosthenes](src/main/java/com/thealgorithms/maths/SieveOfEratosthenes.java)
- 📄 [SimpsonIntegration](src/main/java/com/thealgorithms/maths/SimpsonIntegration.java)
+ - 📄 [SmithNumber](src/main/java/com/thealgorithms/maths/SmithNumber.java)
- 📄 [SolovayStrassenPrimalityTest](src/main/java/com/thealgorithms/maths/SolovayStrassenPrimalityTest.java)
- 📄 [SquareRootWithBabylonianMethod](src/main/java/com/thealgorithms/maths/SquareRootWithBabylonianMethod.java)
- 📄 [SquareRootWithNewtonRaphsonMethod](src/main/java/com/thealgorithms/maths/SquareRootWithNewtonRaphsonMethod.java)
@@ -622,7 +628,6 @@
- 📄 [ProjectileMotion](src/main/java/com/thealgorithms/physics/ProjectileMotion.java)
- 📄 [SimplePendulumRK4](src/main/java/com/thealgorithms/physics/SimplePendulumRK4.java)
- 📁 **puzzlesandgames**
- - 📄 [Sudoku](src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java)
- 📄 [TowerOfHanoi](src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java)
- 📄 [WordBoggle](src/main/java/com/thealgorithms/puzzlesandgames/WordBoggle.java)
- 📁 **randomized**
@@ -842,6 +847,8 @@
- 📄 [PermutationTest](src/test/java/com/thealgorithms/backtracking/PermutationTest.java)
- 📄 [PowerSumTest](src/test/java/com/thealgorithms/backtracking/PowerSumTest.java)
- 📄 [SubsequenceFinderTest](src/test/java/com/thealgorithms/backtracking/SubsequenceFinderTest.java)
+ - 📄 [SudokuSolverTest](src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java)
+ - 📄 [UniquePermutationTest](src/test/java/com/thealgorithms/backtracking/UniquePermutationTest.java)
- 📄 [WordPatternMatcherTest](src/test/java/com/thealgorithms/backtracking/WordPatternMatcherTest.java)
- 📄 [WordSearchTest](src/test/java/com/thealgorithms/backtracking/WordSearchTest.java)
- 📁 **bitmanipulation**
@@ -944,6 +951,7 @@
- 📄 [OctalToHexadecimalTest](src/test/java/com/thealgorithms/conversions/OctalToHexadecimalTest.java)
- 📄 [PhoneticAlphabetConverterTest](src/test/java/com/thealgorithms/conversions/PhoneticAlphabetConverterTest.java)
- 📄 [RomanToIntegerTest](src/test/java/com/thealgorithms/conversions/RomanToIntegerTest.java)
+ - 📄 [TemperatureConverterTest](src/test/java/com/thealgorithms/conversions/TemperatureConverterTest.java)
- 📄 [TimeConverterTest](src/test/java/com/thealgorithms/conversions/TimeConverterTest.java)
- 📄 [TurkishToLatinConversionTest](src/test/java/com/thealgorithms/conversions/TurkishToLatinConversionTest.java)
- 📄 [UnitConversionsTest](src/test/java/com/thealgorithms/conversions/UnitConversionsTest.java)
@@ -1009,6 +1017,7 @@
- 📄 [FibonacciHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/FibonacciHeapTest.java)
- 📄 [GenericHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/GenericHeapTest.java)
- 📄 [HeapElementTest](src/test/java/com/thealgorithms/datastructures/heaps/HeapElementTest.java)
+ - 📄 [IndexedPriorityQueueTest](src/test/java/com/thealgorithms/datastructures/heaps/IndexedPriorityQueueTest.java)
- 📄 [KthElementFinderTest](src/test/java/com/thealgorithms/datastructures/heaps/KthElementFinderTest.java)
- 📄 [LeftistHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/LeftistHeapTest.java)
- 📄 [MaxHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/MaxHeapTest.java)
@@ -1279,6 +1288,7 @@
- 📄 [PiApproximationTest](src/test/java/com/thealgorithms/maths/PiApproximationTest.java)
- 📄 [PollardRhoTest](src/test/java/com/thealgorithms/maths/PollardRhoTest.java)
- 📄 [PowTest](src/test/java/com/thealgorithms/maths/PowTest.java)
+ - 📄 [PowerOfFourTest](src/test/java/com/thealgorithms/maths/PowerOfFourTest.java)
- 📄 [PowerOfTwoOrNotTest](src/test/java/com/thealgorithms/maths/PowerOfTwoOrNotTest.java)
- 📄 [PowerUsingRecursionTest](src/test/java/com/thealgorithms/maths/PowerUsingRecursionTest.java)
- 📄 [PronicNumberTest](src/test/java/com/thealgorithms/maths/PronicNumberTest.java)
@@ -1288,6 +1298,7 @@
- 📄 [SecondMinMaxTest](src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java)
- 📄 [SieveOfAtkinTest](src/test/java/com/thealgorithms/maths/SieveOfAtkinTest.java)
- 📄 [SieveOfEratosthenesTest](src/test/java/com/thealgorithms/maths/SieveOfEratosthenesTest.java)
+ - 📄 [SmithNumberTest](src/test/java/com/thealgorithms/maths/SmithNumberTest.java)
- 📄 [SolovayStrassenPrimalityTestTest](src/test/java/com/thealgorithms/maths/SolovayStrassenPrimalityTestTest.java)
- 📄 [SquareFreeIntegerTest](src/test/java/com/thealgorithms/maths/SquareFreeIntegerTest.java)
- 📄 [SquareRootWithNewtonRaphsonTestMethod](src/test/java/com/thealgorithms/maths/SquareRootWithNewtonRaphsonTestMethod.java)
@@ -1377,7 +1388,6 @@
- 📄 [ProjectileMotionTest](src/test/java/com/thealgorithms/physics/ProjectileMotionTest.java)
- 📄 [SimplePendulumRK4Test](src/test/java/com/thealgorithms/physics/SimplePendulumRK4Test.java)
- 📁 **puzzlesandgames**
- - 📄 [SudokuTest](src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java)
- 📄 [TowerOfHanoiTest](src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java)
- 📄 [WordBoggleTest](src/test/java/com/thealgorithms/puzzlesandgames/WordBoggleTest.java)
- 📁 **randomized**
From fba6292ebc849dc8311ab24d8bcbf6e3dacbc105 Mon Sep 17 00:00:00 2001
From: Piotr Idzik <65706193+vil02@users.noreply.github.com>
Date: Wed, 19 Nov 2025 19:31:32 +0100
Subject: [PATCH 172/272] chore: pin infer to more recent hash (#7079)
* chore: pin infer to more recent hash
* chore: suppress new infer warnings
---
.github/workflows/infer.yml | 2 +-
.inferconfig | 5 +++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/infer.yml b/.github/workflows/infer.yml
index 3df7c4b1fc9e..329fb0cd720a 100644
--- a/.github/workflows/infer.yml
+++ b/.github/workflows/infer.yml
@@ -44,7 +44,7 @@ jobs:
cd ..
git clone https://github.com/facebook/infer.git
cd infer
- git checkout 01aaa268f9d38723ba69c139e10f9e2a04b40b1c
+ git checkout 02c2c43b71e4c5110c0be841e66153942fda06c9
./build-infer.sh java
cp -r infer ../Java
diff --git a/.inferconfig b/.inferconfig
index 6af4f9e2e818..239172177b38 100644
--- a/.inferconfig
+++ b/.inferconfig
@@ -1,6 +1,8 @@
{
"report-block-list-path-regex": [
"src/main/java/com/thealgorithms/ciphers/a5/CompositeLFSR.java",
+ "src/main/java/com/thealgorithms/compression/ArithmeticCoding.java",
+ "src/main/java/com/thealgorithms/datastructures/caches/FIFOCache.java",
"src/main/java/com/thealgorithms/datastructures/crdt/GCounter.java",
"src/main/java/com/thealgorithms/datastructures/crdt/PNCounter.java",
"src/main/java/com/thealgorithms/datastructures/graphs/KahnsAlgorithm.java",
@@ -8,15 +10,18 @@
"src/main/java/com/thealgorithms/datastructures/lists/DoublyLinkedList.java",
"src/main/java/com/thealgorithms/datastructures/trees/CreateBinaryTreeFromInorderPreorder.java",
"src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java",
+ "src/main/java/com/thealgorithms/dynamicprogramming/DamerauLevenshteinDistance.java",
"src/main/java/com/thealgorithms/dynamicprogramming/Fibonacci.java",
"src/main/java/com/thealgorithms/maths/SimpsonIntegration.java",
"src/main/java/com/thealgorithms/others/Dijkstra.java",
"src/main/java/com/thealgorithms/sorts/TopologicalSort.java",
"src/main/java/com/thealgorithms/strings/AhoCorasick.java",
+ "src/test/java/com/thealgorithms/compression/ShannonFanoTest.java",
"src/test/java/com/thealgorithms/datastructures/caches/LRUCacheTest.java",
"src/test/java/com/thealgorithms/datastructures/lists/SkipListTest.java",
"src/test/java/com/thealgorithms/datastructures/trees/KDTreeTest.java",
"src/test/java/com/thealgorithms/datastructures/trees/LazySegmentTreeTest.java",
+ "src/test/java/com/thealgorithms/others/HuffmanTest.java",
"src/test/java/com/thealgorithms/searches/QuickSelectTest.java",
"src/test/java/com/thealgorithms/stacks/PostfixToInfixTest.java",
"src/test/java/com/thealgorithms/strings/HorspoolSearchTest.java"
From e6c576c50aac098f84a1e6a02d81c714750100ab Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 20 Nov 2025 19:44:44 +0100
Subject: [PATCH 173/272] chore(deps): bump actions/checkout from 5 to 6 in
/.github/workflows (#7084)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)
---
updated-dependencies:
- dependency-name: actions/checkout
dependency-version: '6'
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.github/workflows/build.yml | 2 +-
.github/workflows/clang-format-lint.yml | 2 +-
.github/workflows/codeql.yml | 4 ++--
.github/workflows/infer.yml | 2 +-
.github/workflows/project_structure.yml | 2 +-
.github/workflows/update-directorymd.yml | 2 +-
6 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 39bde758d68e..c5f200c12836 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -8,7 +8,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
with:
diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml
index ca014e115282..dc0c9754ed1b 100644
--- a/.github/workflows/clang-format-lint.yml
+++ b/.github/workflows/clang-format-lint.yml
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- uses: DoozyX/clang-format-lint-action@v0.20
with:
source: './src'
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 3a4cfd829b6b..152d0d766fd2 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -21,7 +21,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
@@ -52,7 +52,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
diff --git a/.github/workflows/infer.yml b/.github/workflows/infer.yml
index 329fb0cd720a..c85b1d225f72 100644
--- a/.github/workflows/infer.yml
+++ b/.github/workflows/infer.yml
@@ -15,7 +15,7 @@ jobs:
run_infer:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- name: Set up JDK
uses: actions/setup-java@v5
diff --git a/.github/workflows/project_structure.yml b/.github/workflows/project_structure.yml
index f9fb82a2781c..5aadc6353791 100644
--- a/.github/workflows/project_structure.yml
+++ b/.github/workflows/project_structure.yml
@@ -15,7 +15,7 @@ jobs:
check_structure:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: '3.13'
diff --git a/.github/workflows/update-directorymd.yml b/.github/workflows/update-directorymd.yml
index 6692a884a867..f6c91abe0e74 100644
--- a/.github/workflows/update-directorymd.yml
+++ b/.github/workflows/update-directorymd.yml
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Run Directory Tree Generator
uses: DenizAltunkapan/directory-tree-generator@v2
From fa8ea8e6143ee788eb752178b2252faa41e546cf Mon Sep 17 00:00:00 2001
From: KANAKALA SAI KIRAN <2400030639@kluniversity.in>
Date: Sat, 22 Nov 2025 15:14:34 +0530
Subject: [PATCH 174/272] Feature/centroid decomposition (#7086)
* feat: Add Centroid Decomposition for trees (#7054)
- Implement CentroidDecomposition with O(N log N) construction
- Add CentroidTree class with parent tracking and query methods
- Include buildFromEdges helper for easy tree construction
- Add comprehensive test suite with 20+ test cases
- Cover edge cases, validation, and various tree structures
Closes #7054
* feat: Add Centroid Decomposition for trees (#7054)
- Implement CentroidDecomposition with O(N log N) construction
- Add CentroidTree class with parent tracking and query methods
- Include buildFromEdges helper for easy tree construction
- Add comprehensive test suite with 20+ test cases
- Cover edge cases, validation, and various tree structures
Closes #7054
* fix: Remove trailing whitespace from CentroidDecompositionTest
* fix: Remove trailing whitespace and add newlines at end of files
* fix: Format code to comply with clang-format and checkstyle requirements
* style: Fix lambda formatting in test assertions
- Change single-line lambdas to multi-line format
- Align with repository code style guidelines
* style: Apply clang-format to match repository style guide
- Format code according to .clang-format configuration
- Use single-line lambdas as allowed by AllowShortLambdasOnASingleLine: All
- Apply 4-space indentation
- Ensure proper line endings
---
.../trees/CentroidDecomposition.java | 217 ++++++++++++++++
.../trees/CentroidDecompositionTest.java | 236 ++++++++++++++++++
2 files changed, 453 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/datastructures/trees/CentroidDecomposition.java
create mode 100644 src/test/java/com/thealgorithms/datastructures/trees/CentroidDecompositionTest.java
diff --git a/src/main/java/com/thealgorithms/datastructures/trees/CentroidDecomposition.java b/src/main/java/com/thealgorithms/datastructures/trees/CentroidDecomposition.java
new file mode 100644
index 000000000000..0b29dd6f5f5e
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/trees/CentroidDecomposition.java
@@ -0,0 +1,217 @@
+package com.thealgorithms.datastructures.trees;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Centroid Decomposition is a divide-and-conquer technique for trees.
+ * It recursively partitions a tree by finding centroids - nodes whose removal
+ * creates balanced subtrees (each with at most N/2 nodes).
+ *
+ *
+ * Time Complexity: O(N log N) for construction
+ * Space Complexity: O(N)
+ *
+ *
+ * Applications:
+ * - Distance queries on trees
+ * - Path counting problems
+ * - Nearest neighbor searches
+ *
+ * @see Centroid Decomposition
+ * @see Centroid Decomposition Tutorial
+ * @author lens161
+ */
+public final class CentroidDecomposition {
+
+ private CentroidDecomposition() {
+ }
+
+ /**
+ * Represents the centroid tree structure.
+ */
+ public static final class CentroidTree {
+ private final int n;
+ private final List> adj;
+ private final int[] parent;
+ private final int[] subtreeSize;
+ private final boolean[] removed;
+ private int root;
+
+ /**
+ * Constructs a centroid tree from an adjacency list.
+ *
+ * @param adj adjacency list representation of the tree (0-indexed)
+ * @throws IllegalArgumentException if tree is empty or null
+ */
+ public CentroidTree(List> adj) {
+ if (adj == null || adj.isEmpty()) {
+ throw new IllegalArgumentException("Tree cannot be empty or null");
+ }
+
+ this.n = adj.size();
+ this.adj = adj;
+ this.parent = new int[n];
+ this.subtreeSize = new int[n];
+ this.removed = new boolean[n];
+ Arrays.fill(parent, -1);
+
+ // Build centroid tree starting from node 0
+ this.root = decompose(0, -1);
+ }
+
+ /**
+ * Recursively builds the centroid tree.
+ *
+ * @param u current node
+ * @param p parent in centroid tree
+ * @return centroid of current component
+ */
+ private int decompose(int u, int p) {
+ int size = getSubtreeSize(u, -1);
+ int centroid = findCentroid(u, -1, size);
+
+ removed[centroid] = true;
+ parent[centroid] = p;
+
+ // Recursively decompose each subtree
+ for (int v : adj.get(centroid)) {
+ if (!removed[v]) {
+ decompose(v, centroid);
+ }
+ }
+
+ return centroid;
+ }
+
+ /**
+ * Calculates subtree size from node u.
+ *
+ * @param u current node
+ * @param p parent node (-1 for root)
+ * @return size of subtree rooted at u
+ */
+ private int getSubtreeSize(int u, int p) {
+ subtreeSize[u] = 1;
+ for (int v : adj.get(u)) {
+ if (v != p && !removed[v]) {
+ subtreeSize[u] += getSubtreeSize(v, u);
+ }
+ }
+ return subtreeSize[u];
+ }
+
+ /**
+ * Finds the centroid of a subtree.
+ * A centroid is a node whose removal creates components with size <= totalSize/2.
+ *
+ * @param u current node
+ * @param p parent node
+ * @param totalSize total size of current component
+ * @return centroid node
+ */
+ private int findCentroid(int u, int p, int totalSize) {
+ for (int v : adj.get(u)) {
+ if (v != p && !removed[v] && subtreeSize[v] > totalSize / 2) {
+ return findCentroid(v, u, totalSize);
+ }
+ }
+ return u;
+ }
+
+ /**
+ * Gets the parent of a node in the centroid tree.
+ *
+ * @param node the node
+ * @return parent node in centroid tree, or -1 if root
+ */
+ public int getParent(int node) {
+ if (node < 0 || node >= n) {
+ throw new IllegalArgumentException("Invalid node: " + node);
+ }
+ return parent[node];
+ }
+
+ /**
+ * Gets the root of the centroid tree.
+ *
+ * @return root node
+ */
+ public int getRoot() {
+ return root;
+ }
+
+ /**
+ * Gets the number of nodes in the tree.
+ *
+ * @return number of nodes
+ */
+ public int size() {
+ return n;
+ }
+
+ /**
+ * Returns the centroid tree structure as a string.
+ * Format: node -> parent (or ROOT for root node)
+ *
+ * @return string representation
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("Centroid Tree:\n");
+ for (int i = 0; i < n; i++) {
+ sb.append("Node ").append(i).append(" -> ");
+ if (parent[i] == -1) {
+ sb.append("ROOT");
+ } else {
+ sb.append("Parent ").append(parent[i]);
+ }
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+ }
+
+ /**
+ * Creates a centroid tree from an edge list.
+ *
+ * @param n number of nodes (0-indexed: 0 to n-1)
+ * @param edges list of edges where each edge is [u, v]
+ * @return CentroidTree object
+ * @throws IllegalArgumentException if n <= 0 or edges is invalid
+ */
+ public static CentroidTree buildFromEdges(int n, int[][] edges) {
+ if (n <= 0) {
+ throw new IllegalArgumentException("Number of nodes must be positive");
+ }
+ if (edges == null) {
+ throw new IllegalArgumentException("Edges cannot be null");
+ }
+ if (edges.length != n - 1) {
+ throw new IllegalArgumentException("Tree must have exactly n-1 edges");
+ }
+
+ List> adj = new ArrayList<>();
+ for (int i = 0; i < n; i++) {
+ adj.add(new ArrayList<>());
+ }
+
+ for (int[] edge : edges) {
+ if (edge.length != 2) {
+ throw new IllegalArgumentException("Each edge must have exactly 2 nodes");
+ }
+ int u = edge[0];
+ int v = edge[1];
+
+ if (u < 0 || u >= n || v < 0 || v >= n) {
+ throw new IllegalArgumentException("Invalid node in edge: [" + u + ", " + v + "]");
+ }
+
+ adj.get(u).add(v);
+ adj.get(v).add(u);
+ }
+
+ return new CentroidTree(adj);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/trees/CentroidDecompositionTest.java b/src/test/java/com/thealgorithms/datastructures/trees/CentroidDecompositionTest.java
new file mode 100644
index 000000000000..43d732e54f34
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/trees/CentroidDecompositionTest.java
@@ -0,0 +1,236 @@
+package com.thealgorithms.datastructures.trees;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test cases for CentroidDecomposition
+ *
+ * @author lens161
+ */
+class CentroidDecompositionTest {
+
+ @Test
+ void testSingleNode() {
+ // Tree with just one node
+ int[][] edges = {};
+ CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(1, edges);
+
+ assertEquals(1, tree.size());
+ assertEquals(0, tree.getRoot());
+ assertEquals(-1, tree.getParent(0));
+ }
+
+ @Test
+ void testTwoNodes() {
+ // Simple tree: 0 - 1
+ int[][] edges = {{0, 1}};
+ CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(2, edges);
+
+ assertEquals(2, tree.size());
+ int root = tree.getRoot();
+ assertTrue(root == 0 || root == 1, "Root should be either node 0 or 1");
+
+ // One node should be root, other should have the root as parent
+ int nonRoot = (root == 0) ? 1 : 0;
+ assertEquals(-1, tree.getParent(root));
+ assertEquals(root, tree.getParent(nonRoot));
+ }
+
+ @Test
+ void testLinearTree() {
+ // Linear tree: 0 - 1 - 2 - 3 - 4
+ int[][] edges = {{0, 1}, {1, 2}, {2, 3}, {3, 4}};
+ CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(5, edges);
+
+ assertEquals(5, tree.size());
+ // For a linear tree of 5 nodes, the centroid should be the middle node (node 2)
+ assertEquals(2, tree.getRoot());
+ assertEquals(-1, tree.getParent(2));
+ }
+
+ @Test
+ void testBalancedBinaryTree() {
+ // Balanced binary tree:
+ // 0
+ // / \
+ // 1 2
+ // / \
+ // 3 4
+ int[][] edges = {{0, 1}, {0, 2}, {1, 3}, {1, 4}};
+ CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(5, edges);
+
+ assertEquals(5, tree.size());
+ // Root should be 0 or 1 (both are valid centroids)
+ int root = tree.getRoot();
+ assertTrue(root == 0 || root == 1);
+ assertEquals(-1, tree.getParent(root));
+
+ // All nodes should have a parent in centroid tree except root
+ for (int i = 0; i < 5; i++) {
+ if (i != root) {
+ assertTrue(tree.getParent(i) >= 0 && tree.getParent(i) < 5);
+ }
+ }
+ }
+
+ @Test
+ void testStarTree() {
+ // Star tree: center node 0 connected to 1, 2, 3, 4
+ int[][] edges = {{0, 1}, {0, 2}, {0, 3}, {0, 4}};
+ CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(5, edges);
+
+ assertEquals(5, tree.size());
+ // Center node (0) should be the root
+ assertEquals(0, tree.getRoot());
+
+ // All other nodes should have 0 as parent
+ for (int i = 1; i < 5; i++) {
+ assertEquals(0, tree.getParent(i));
+ }
+ }
+
+ @Test
+ void testCompleteTree() {
+ // Complete binary tree of 7 nodes:
+ // 0
+ // / \
+ // 1 2
+ // / \ / \
+ // 3 4 5 6
+ int[][] edges = {{0, 1}, {0, 2}, {1, 3}, {1, 4}, {2, 5}, {2, 6}};
+ CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(7, edges);
+
+ assertEquals(7, tree.size());
+ assertEquals(0, tree.getRoot()); // Root should be the center
+
+ // Verify all nodes are reachable in centroid tree
+ boolean[] visited = new boolean[7];
+ visited[0] = true;
+ for (int i = 1; i < 7; i++) {
+ int parent = tree.getParent(i);
+ assertTrue(parent >= 0 && parent < 7);
+ assertTrue(visited[parent], "Parent should be processed before child");
+ visited[i] = true;
+ }
+ }
+
+ @Test
+ void testLargerTree() {
+ // Tree with 10 nodes
+ int[][] edges = {{0, 1}, {0, 2}, {1, 3}, {1, 4}, {2, 5}, {2, 6}, {3, 7}, {4, 8}, {5, 9}};
+ CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(10, edges);
+
+ assertEquals(10, tree.size());
+ int root = tree.getRoot();
+ assertTrue(root >= 0 && root < 10);
+ assertEquals(-1, tree.getParent(root));
+
+ // Verify centroid tree structure is valid
+ for (int i = 0; i < 10; i++) {
+ if (i != root) {
+ assertTrue(tree.getParent(i) >= -1 && tree.getParent(i) < 10);
+ }
+ }
+ }
+
+ @Test
+ void testPathGraph() {
+ // Path graph with 8 nodes: 0-1-2-3-4-5-6-7
+ int[][] edges = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 5}, {5, 6}, {6, 7}};
+ CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(8, edges);
+
+ assertEquals(8, tree.size());
+ // For path of 8 nodes, centroid should be around middle
+ int root = tree.getRoot();
+ assertTrue(root >= 2 && root <= 5, "Root should be near the middle of path");
+ }
+
+ @Test
+ void testInvalidEmptyTree() {
+ assertThrows(IllegalArgumentException.class, () -> { CentroidDecomposition.buildFromEdges(0, new int[][] {}); });
+ }
+
+ @Test
+ void testInvalidNegativeNodes() {
+ assertThrows(IllegalArgumentException.class, () -> { CentroidDecomposition.buildFromEdges(-1, new int[][] {}); });
+ }
+
+ @Test
+ void testInvalidNullEdges() {
+ assertThrows(IllegalArgumentException.class, () -> { CentroidDecomposition.buildFromEdges(5, null); });
+ }
+
+ @Test
+ void testInvalidEdgeCount() {
+ // Tree with n nodes must have n-1 edges
+ int[][] edges = {{0, 1}, {1, 2}}; // 2 edges for 5 nodes (should be 4)
+ assertThrows(IllegalArgumentException.class, () -> { CentroidDecomposition.buildFromEdges(5, edges); });
+ }
+
+ @Test
+ void testInvalidEdgeFormat() {
+ int[][] edges = {{0, 1, 2}}; // Edge with 3 elements instead of 2
+ assertThrows(IllegalArgumentException.class, () -> { CentroidDecomposition.buildFromEdges(3, edges); });
+ }
+
+ @Test
+ void testInvalidNodeInEdge() {
+ int[][] edges = {{0, 5}}; // Node 5 doesn't exist in tree of size 3
+ assertThrows(IllegalArgumentException.class, () -> { CentroidDecomposition.buildFromEdges(3, edges); });
+ }
+
+ @Test
+ void testInvalidNodeQuery() {
+ int[][] edges = {{0, 1}, {1, 2}};
+ CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(3, edges);
+
+ assertThrows(IllegalArgumentException.class, () -> { tree.getParent(-1); });
+
+ assertThrows(IllegalArgumentException.class, () -> { tree.getParent(5); });
+ }
+
+ @Test
+ void testToString() {
+ int[][] edges = {{0, 1}, {1, 2}};
+ CentroidDecomposition.CentroidTree tree = CentroidDecomposition.buildFromEdges(3, edges);
+
+ String result = tree.toString();
+ assertNotNull(result);
+ assertTrue(result.contains("Centroid Tree"));
+ assertTrue(result.contains("Node"));
+ assertTrue(result.contains("ROOT"));
+ }
+
+ @Test
+ void testAdjacencyListConstructor() {
+ List> adj = new ArrayList<>();
+ for (int i = 0; i < 3; i++) {
+ adj.add(new ArrayList<>());
+ }
+ adj.get(0).add(1);
+ adj.get(1).add(0);
+ adj.get(1).add(2);
+ adj.get(2).add(1);
+
+ CentroidDecomposition.CentroidTree tree = new CentroidDecomposition.CentroidTree(adj);
+ assertEquals(3, tree.size());
+ assertEquals(1, tree.getRoot());
+ }
+
+ @Test
+ void testNullAdjacencyList() {
+ assertThrows(IllegalArgumentException.class, () -> { new CentroidDecomposition.CentroidTree(null); });
+ }
+
+ @Test
+ void testEmptyAdjacencyList() {
+ assertThrows(IllegalArgumentException.class, () -> { new CentroidDecomposition.CentroidTree(new ArrayList<>()); });
+ }
+}
From f693c44b539508cd262374a6d8e9d7329301d6cc Mon Sep 17 00:00:00 2001
From: Deniz Altunkapan
Date: Sat, 22 Nov 2025 18:26:16 +0100
Subject: [PATCH 175/272] fix: prevent duplicate auth header in GitHub Actions
workflow (#7091)
---
.github/workflows/update-directorymd.yml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/update-directorymd.yml b/.github/workflows/update-directorymd.yml
index f6c91abe0e74..101d82427e38 100644
--- a/.github/workflows/update-directorymd.yml
+++ b/.github/workflows/update-directorymd.yml
@@ -1,4 +1,4 @@
-name: Generate Directory Markdown
+name: Generate Directory Markdown
on:
push:
@@ -15,6 +15,8 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v6
+ with:
+ persist-credentials: false
- name: Run Directory Tree Generator
uses: DenizAltunkapan/directory-tree-generator@v2
From 1c6026ecc640b26d21bf5386872ef99de3d42c60 Mon Sep 17 00:00:00 2001
From: Eswar Venkata Ram Charan Seeram
Date: Tue, 25 Nov 2025 01:46:16 +0530
Subject: [PATCH 176/272] fix: correct error message in surfaceAreaCylinder
method (#7106)
---
src/main/java/com/thealgorithms/maths/Area.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/maths/Area.java b/src/main/java/com/thealgorithms/maths/Area.java
index a34ad6b01ab5..1eba6666dde3 100644
--- a/src/main/java/com/thealgorithms/maths/Area.java
+++ b/src/main/java/com/thealgorithms/maths/Area.java
@@ -96,7 +96,7 @@ public static double surfaceAreaCylinder(final double radius, final double heigh
throw new IllegalArgumentException(POSITIVE_RADIUS);
}
if (height <= 0) {
- throw new IllegalArgumentException(POSITIVE_RADIUS);
+ throw new IllegalArgumentException(POSITIVE_HEIGHT);
}
return 2 * (Math.PI * radius * radius + Math.PI * radius * height);
}
From 2c4bf3c7c88b2f3b7bfa6baeebb7b569e0530a5a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 25 Nov 2025 16:36:37 +0100
Subject: [PATCH 177/272] chore(deps): bump
com.github.spotbugs:spotbugs-maven-plugin from 4.9.8.1 to 4.9.8.2 (#7109)
chore(deps): bump com.github.spotbugs:spotbugs-maven-plugin
Bumps [com.github.spotbugs:spotbugs-maven-plugin](https://github.com/spotbugs/spotbugs-maven-plugin) from 4.9.8.1 to 4.9.8.2.
- [Release notes](https://github.com/spotbugs/spotbugs-maven-plugin/releases)
- [Commits](https://github.com/spotbugs/spotbugs-maven-plugin/compare/spotbugs-maven-plugin-4.9.8.1...spotbugs-maven-plugin-4.9.8.2)
---
updated-dependencies:
- dependency-name: com.github.spotbugs:spotbugs-maven-plugin
dependency-version: 4.9.8.2
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 774db2ec4403..eb2aafc0fcc0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -119,7 +119,7 @@
com.github.spotbugs
spotbugs-maven-plugin
- 4.9.8.1
+ 4.9.8.2
spotbugs-exclude.xml
true
From a14e1e37669f0d8841e4a5bae07726da21e64736 Mon Sep 17 00:00:00 2001
From: prasanth-30011
Date: Wed, 26 Nov 2025 16:51:07 +0530
Subject: [PATCH 178/272] docs: improve javadoc for Combination class (#7126)
Updated class documentation to reflect that the class finds combinations instead of permutations.
---
src/main/java/com/thealgorithms/backtracking/Combination.java | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/main/java/com/thealgorithms/backtracking/Combination.java b/src/main/java/com/thealgorithms/backtracking/Combination.java
index ecaf7428f986..377d2c862d54 100644
--- a/src/main/java/com/thealgorithms/backtracking/Combination.java
+++ b/src/main/java/com/thealgorithms/backtracking/Combination.java
@@ -7,8 +7,7 @@
import java.util.TreeSet;
/**
- * Finds all permutations of given array
- * @author Alan Piao (git-Alan Piao)
+ * Finds all combinations of a given array using backtracking algorithm * @author Alan Piao (git-Alan Piao)
*/
public final class Combination {
private Combination() {
From e841d73837c17d462e8bdfbb4d601e6744082981 Mon Sep 17 00:00:00 2001
From: Jayana Anjani Pavan Vardhan Naidu
Date: Thu, 27 Nov 2025 16:55:52 +0530
Subject: [PATCH 179/272] Update Javadoc for perimeterIrregularPolygon method
(#7141)
Fixed incorrect @return description in perimeterIrregularPolygon method javadoc. Changed "trapezoid" to "irregular polygon" to accurately reflect what the method calculates.
---
src/main/java/com/thealgorithms/maths/Perimeter.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/thealgorithms/maths/Perimeter.java b/src/main/java/com/thealgorithms/maths/Perimeter.java
index f8aa1876d388..670851eb346b 100644
--- a/src/main/java/com/thealgorithms/maths/Perimeter.java
+++ b/src/main/java/com/thealgorithms/maths/Perimeter.java
@@ -27,7 +27,7 @@ public static float perimeterRegularPolygon(int n, float side) {
* @param side2 for length of side 2
* @param side3 for length of side 3
* @param sides for length of remaining sides
- * @return Perimeter of given trapezoid.
+ * @return Perimeter of given irregular polygon.
*/
public static float perimeterIrregularPolygon(float side1, float side2, float side3, float... sides) {
float perimeter = side1 + side2 + side3;
From d1ea3069203b5d2a132f2cf553424fbf4c2e3353 Mon Sep 17 00:00:00 2001
From: Gokul45-45 <2400032465@kluniversity.in>
Date: Thu, 27 Nov 2025 16:59:48 +0530
Subject: [PATCH 180/272] feat: add Valid Parentheses algorithm using Stack
(#7117)
* feat: add Valid Parentheses algorithm using Stack
* fix: add missing ValidParentheses.java implementation
* fix: remove trailing spaces and add newline at EOF
* fix: remove misplaced ValidParentheses.java from root
---
.../stacks/ValidParentheses.java | 74 +++++++++++++++++++
.../stacks/ValidParenthesesTest.java | 32 ++++++++
2 files changed, 106 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/stacks/ValidParentheses.java
create mode 100644 src/test/java/com/thealgorithms/stacks/ValidParenthesesTest.java
diff --git a/src/main/java/com/thealgorithms/stacks/ValidParentheses.java b/src/main/java/com/thealgorithms/stacks/ValidParentheses.java
new file mode 100644
index 000000000000..2cc616a38826
--- /dev/null
+++ b/src/main/java/com/thealgorithms/stacks/ValidParentheses.java
@@ -0,0 +1,74 @@
+package com.thealgorithms.stacks;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Stack;
+
+/**
+ * Valid Parentheses Problem
+ *
+ * Given a string containing just the characters '(', ')', '{', '}', '[' and ']',
+ * determine if the input string is valid.
+ *
+ * An input string is valid if:
+ * 1. Open brackets must be closed by the same type of brackets.
+ * 2. Open brackets must be closed in the correct order.
+ * 3. Every close bracket has a corresponding open bracket of the same type.
+ *
+ * Examples:
+ * Input: "()"
+ * Output: true
+ *
+ * Input: "()[]{}"
+ * Output: true
+ *
+ * Input: "(]"
+ * Output: false
+ *
+ * Input: "([)]"
+ * Output: false
+ *
+ * @author Gokul45-45
+ */
+public final class ValidParentheses {
+ private ValidParentheses() {
+ }
+
+ /**
+ * Checks if the given string has valid parentheses
+ *
+ * @param s the input string containing parentheses
+ * @return true if valid, false otherwise
+ */
+ public static boolean isValid(String s) {
+ if (s == null || s.length() % 2 != 0) {
+ return false;
+ }
+
+ Map parenthesesMap = new HashMap<>();
+ parenthesesMap.put('(', ')');
+ parenthesesMap.put('{', '}');
+ parenthesesMap.put('[', ']');
+
+ Stack stack = new Stack<>();
+
+ for (char c : s.toCharArray()) {
+ if (parenthesesMap.containsKey(c)) {
+ // Opening bracket - push to stack
+ stack.push(c);
+ } else {
+ // Closing bracket - check if it matches
+ if (stack.isEmpty()) {
+ return false;
+ }
+ char openBracket = stack.pop();
+ if (parenthesesMap.get(openBracket) != c) {
+ return false;
+ }
+ }
+ }
+
+ // Stack should be empty if all brackets are matched
+ return stack.isEmpty();
+ }
+}
diff --git a/src/test/java/com/thealgorithms/stacks/ValidParenthesesTest.java b/src/test/java/com/thealgorithms/stacks/ValidParenthesesTest.java
new file mode 100644
index 000000000000..39014780caa9
--- /dev/null
+++ b/src/test/java/com/thealgorithms/stacks/ValidParenthesesTest.java
@@ -0,0 +1,32 @@
+package com.thealgorithms.stacks;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+class ValidParenthesesTest {
+
+ @Test
+ void testValidParentheses() {
+ assertTrue(ValidParentheses.isValid("()"));
+ assertTrue(ValidParentheses.isValid("()[]{}"));
+ assertTrue(ValidParentheses.isValid("{[]}"));
+ assertTrue(ValidParentheses.isValid(""));
+ }
+
+ @Test
+ void testInvalidParentheses() {
+ assertFalse(ValidParentheses.isValid("(]"));
+ assertFalse(ValidParentheses.isValid("([)]"));
+ assertFalse(ValidParentheses.isValid("{{{"));
+ assertFalse(ValidParentheses.isValid("}"));
+ assertFalse(ValidParentheses.isValid("("));
+ }
+
+ @Test
+ void testNullAndOddLength() {
+ assertFalse(ValidParentheses.isValid(null));
+ assertFalse(ValidParentheses.isValid("(()"));
+ }
+}
From f352f8111ba3fdcc87674263c0907f9452f5b0b2 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 28 Nov 2025 09:26:07 +0100
Subject: [PATCH 181/272] chore(deps): bump
com.mebigfatguy.fb-contrib:fb-contrib from 7.7.0 to 7.7.1 (#7144)
chore(deps): bump com.mebigfatguy.fb-contrib:fb-contrib
Bumps [com.mebigfatguy.fb-contrib:fb-contrib](https://github.com/mebigfatguy/fb-contrib) from 7.7.0 to 7.7.1.
- [Commits](https://github.com/mebigfatguy/fb-contrib/commits)
---
updated-dependencies:
- dependency-name: com.mebigfatguy.fb-contrib:fb-contrib
dependency-version: 7.7.1
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index eb2aafc0fcc0..6b918cdad5bb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -127,7 +127,7 @@
com.mebigfatguy.fb-contrib
fb-contrib
- 7.7.0
+ 7.7.1
com.h3xstream.findsecbugs
From 4c5525a2e0a9b18b879d774398d1a0f5ca29c509 Mon Sep 17 00:00:00 2001
From: Sameer Prajapati
Date: Fri, 28 Nov 2025 14:17:53 +0530
Subject: [PATCH 182/272] =?UTF-8?q?feat:=20Added=20Gomory=E2=80=93Hu=20Tre?=
=?UTF-8?q?e=20(all-pairs=20min-cuts=20via=20n1=20max-flows)=20(#6818)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Add Gomory–Hu Tree (all-pairs min-cuts via n1 max-flows)
* Stabilize Monte Carlo integration with antithetic variates to reduce variance
* Fix Checkstyle in GomoryHuTreeTest: remove inner assignments, add braces, split declarations
* SpotBugs: use RandomGenerator interface in test helper
---------
Co-authored-by: Deniz Altunkapan
---
DIRECTORY.md | 1 +
.../com/thealgorithms/graph/GomoryHuTree.java | 144 ++++++++++++++++++
.../randomized/MonteCarloIntegration.java | 16 +-
.../thealgorithms/graph/GomoryHuTreeTest.java | 132 ++++++++++++++++
4 files changed, 289 insertions(+), 4 deletions(-)
create mode 100644 src/main/java/com/thealgorithms/graph/GomoryHuTree.java
create mode 100644 src/test/java/com/thealgorithms/graph/GomoryHuTreeTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 042efa72addc..b8db96ffa993 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -385,6 +385,7 @@
- 📄 [Dinic](src/main/java/com/thealgorithms/graph/Dinic.java)
- 📄 [Edmonds](src/main/java/com/thealgorithms/graph/Edmonds.java)
- 📄 [EdmondsKarp](src/main/java/com/thealgorithms/graph/EdmondsKarp.java)
+ - 📄 [GomoryHuTree](src/main/java/com/thealgorithms/graph/GomoryHuTree.java)
- 📄 [HierholzerAlgorithm](src/main/java/com/thealgorithms/graph/HierholzerAlgorithm.java)
- 📄 [HierholzerEulerianPath](src/main/java/com/thealgorithms/graph/HierholzerEulerianPath.java)
- 📄 [HopcroftKarp](src/main/java/com/thealgorithms/graph/HopcroftKarp.java)
diff --git a/src/main/java/com/thealgorithms/graph/GomoryHuTree.java b/src/main/java/com/thealgorithms/graph/GomoryHuTree.java
new file mode 100644
index 000000000000..f8c110f25571
--- /dev/null
+++ b/src/main/java/com/thealgorithms/graph/GomoryHuTree.java
@@ -0,0 +1,144 @@
+package com.thealgorithms.graph;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Queue;
+
+/**
+ * Gomory–Hu tree construction for undirected graphs via n−1 max-flow computations.
+ *
+ * API: {@code buildTree(int[][])} returns {@code {parent, weight}} arrays for the tree.
+ *
+ * @see Wikipedia: Gomory–Hu tree
+ */
+
+public final class GomoryHuTree {
+ private GomoryHuTree() {
+ }
+
+ public static int[][] buildTree(int[][] cap) {
+ validateCapacityMatrix(cap);
+ final int n = cap.length;
+ if (n == 1) {
+ return new int[][] {new int[] {-1}, new int[] {0}};
+ }
+
+ int[] parent = new int[n];
+ int[] weight = new int[n];
+ Arrays.fill(parent, 0);
+ parent[0] = -1;
+ weight[0] = 0;
+
+ for (int s = 1; s < n; s++) {
+ int t = parent[s];
+ MaxFlowResult res = edmondsKarpWithMinCut(cap, s, t);
+ int f = res.flow;
+ weight[s] = f;
+
+ for (int v = 0; v < n; v++) {
+ if (v != s && parent[v] == t && res.reachable[v]) {
+ parent[v] = s;
+ }
+ }
+
+ if (t != 0 && res.reachable[parent[t]]) {
+ parent[s] = parent[t];
+ parent[t] = s;
+ weight[s] = weight[t];
+ weight[t] = f;
+ }
+ }
+ return new int[][] {parent, weight};
+ }
+
+ private static void validateCapacityMatrix(int[][] cap) {
+ if (cap == null || cap.length == 0) {
+ throw new IllegalArgumentException("Capacity matrix must not be null or empty");
+ }
+ final int n = cap.length;
+ for (int i = 0; i < n; i++) {
+ if (cap[i] == null || cap[i].length != n) {
+ throw new IllegalArgumentException("Capacity matrix must be square");
+ }
+ for (int j = 0; j < n; j++) {
+ if (cap[i][j] < 0) {
+ throw new IllegalArgumentException("Capacities must be non-negative");
+ }
+ }
+ }
+ }
+
+ private static final class MaxFlowResult {
+ final int flow;
+ final boolean[] reachable;
+ MaxFlowResult(int flow, boolean[] reachable) {
+ this.flow = flow;
+ this.reachable = reachable;
+ }
+ }
+
+ private static MaxFlowResult edmondsKarpWithMinCut(int[][] capacity, int source, int sink) {
+ final int n = capacity.length;
+ int[][] residual = new int[n][n];
+ for (int i = 0; i < n; i++) {
+ residual[i] = Arrays.copyOf(capacity[i], n);
+ }
+
+ int[] parent = new int[n];
+ int maxFlow = 0;
+
+ while (bfs(residual, source, sink, parent)) {
+ int pathFlow = Integer.MAX_VALUE;
+ for (int v = sink; v != source; v = parent[v]) {
+ int u = parent[v];
+ pathFlow = Math.min(pathFlow, residual[u][v]);
+ }
+ for (int v = sink; v != source; v = parent[v]) {
+ int u = parent[v];
+ residual[u][v] -= pathFlow;
+ residual[v][u] += pathFlow;
+ }
+ maxFlow += pathFlow;
+ }
+
+ boolean[] reachable = new boolean[n];
+ markReachable(residual, source, reachable);
+ return new MaxFlowResult(maxFlow, reachable);
+ }
+
+ private static boolean bfs(int[][] residual, int source, int sink, int[] parent) {
+ Arrays.fill(parent, -1);
+ parent[source] = source;
+ Queue q = new ArrayDeque<>();
+ q.add(source);
+ while (!q.isEmpty()) {
+ int u = q.poll();
+ for (int v = 0; v < residual.length; v++) {
+ if (residual[u][v] > 0 && parent[v] == -1) {
+ parent[v] = u;
+ if (v == sink) {
+ return true;
+ }
+ q.add(v);
+ }
+ }
+ }
+ return false;
+ }
+
+ private static void markReachable(int[][] residual, int source, boolean[] vis) {
+ Arrays.fill(vis, false);
+ Queue q = new ArrayDeque<>();
+ vis[source] = true;
+ q.add(source);
+ while (!q.isEmpty()) {
+ int u = q.poll();
+ for (int v = 0; v < residual.length; v++) {
+ if (!vis[v] && residual[u][v] > 0) {
+ vis[v] = true;
+ q.add(v);
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/randomized/MonteCarloIntegration.java b/src/main/java/com/thealgorithms/randomized/MonteCarloIntegration.java
index 05d7abbbcd6c..06101295e880 100644
--- a/src/main/java/com/thealgorithms/randomized/MonteCarloIntegration.java
+++ b/src/main/java/com/thealgorithms/randomized/MonteCarloIntegration.java
@@ -64,13 +64,21 @@ private static double doApproximate(Function fx, double a, doubl
if (!validate(fx, a, b, n)) {
throw new IllegalArgumentException("Invalid input parameters");
}
- double totalArea = 0.0;
+ double total = 0.0;
double interval = b - a;
- for (int i = 0; i < n; i++) {
+ int pairs = n / 2;
+ for (int i = 0; i < pairs; i++) {
+ double u = generator.nextDouble();
+ double x1 = a + u * interval;
+ double x2 = a + (1.0 - u) * interval;
+ total += fx.apply(x1);
+ total += fx.apply(x2);
+ }
+ if ((n & 1) == 1) {
double x = a + generator.nextDouble() * interval;
- totalArea += fx.apply(x);
+ total += fx.apply(x);
}
- return interval * totalArea / n;
+ return interval * total / n;
}
private static boolean validate(Function fx, double a, double b, int n) {
diff --git a/src/test/java/com/thealgorithms/graph/GomoryHuTreeTest.java b/src/test/java/com/thealgorithms/graph/GomoryHuTreeTest.java
new file mode 100644
index 000000000000..241f23c0fa1d
--- /dev/null
+++ b/src/test/java/com/thealgorithms/graph/GomoryHuTreeTest.java
@@ -0,0 +1,132 @@
+package com.thealgorithms.graph;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Queue;
+import java.util.Random;
+import java.util.random.RandomGenerator;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+class GomoryHuTreeTest {
+
+ @Test
+ @DisplayName("Single node graph")
+ void singleNode() {
+ int[][] cap = {{0}};
+ int[][] res = GomoryHuTree.buildTree(cap);
+ int[] parent = res[0];
+ int[] weight = res[1];
+ assertEquals(-1, parent[0]);
+ assertEquals(0, weight[0]);
+ }
+
+ @Test
+ @DisplayName("Triangle undirected graph with known min-cuts")
+ void triangleGraph() {
+ // 0-1:3, 1-2:2, 0-2:4
+ int[][] cap = new int[3][3];
+ cap[0][1] = 3;
+ cap[1][0] = 3;
+ cap[1][2] = 2;
+ cap[2][1] = 2;
+ cap[0][2] = 4;
+ cap[2][0] = 4;
+
+ int[][] tree = GomoryHuTree.buildTree(cap);
+ // validate all pairs via path-min-edge equals maxflow
+ validateAllPairs(cap, tree);
+ }
+
+ @Test
+ @DisplayName("Random small undirected graphs compare to EdmondsKarp")
+ void randomSmallGraphs() {
+ Random rng = new Random(42);
+ for (int n = 2; n <= 6; n++) {
+ for (int iter = 0; iter < 10; iter++) {
+ int[][] cap = randSymmetricMatrix(n, 0, 5, rng);
+ int[][] tree = GomoryHuTree.buildTree(cap);
+ validateAllPairs(cap, tree);
+ }
+ }
+ }
+
+ private static int[][] randSymmetricMatrix(int n, int lo, int hi, RandomGenerator rng) {
+ int[][] a = new int[n][n];
+ for (int i = 0; i < n; i++) {
+ for (int j = i + 1; j < n; j++) {
+ int w = rng.nextInt(hi - lo + 1) + lo;
+ a[i][j] = w;
+ a[j][i] = w;
+ }
+ }
+ // zero diagonal
+ for (int i = 0; i < n; i++) {
+ a[i][i] = 0;
+ }
+ return a;
+ }
+
+ private static void validateAllPairs(int[][] cap, int[][] tree) {
+ int n = cap.length;
+ int[] parent = tree[0];
+ int[] weight = tree[1];
+
+ // build adjacency list of tree without generic array creation
+ List> g = new ArrayList<>();
+ for (int i = 0; i < n; i++) {
+ g.add(new ArrayList<>());
+ }
+ for (int v = 1; v < n; v++) {
+ int u = parent[v];
+ int w = weight[v];
+ g.get(u).add(new int[] {v, w});
+ g.get(v).add(new int[] {u, w});
+ }
+
+ for (int s = 0; s < n; s++) {
+ for (int t = s + 1; t < n; t++) {
+ int treeVal = minEdgeOnPath(g, s, t);
+ int flowVal = EdmondsKarp.maxFlow(cap, s, t);
+ assertEquals(flowVal, treeVal, "pair (" + s + "," + t + ")");
+ }
+ }
+ }
+
+ private static int minEdgeOnPath(List> g, int s, int t) {
+ // BFS to record parent and edge weight along the path, since it's a tree, unique path exists
+ int n = g.size();
+ int[] parent = new int[n];
+ int[] edgeW = new int[n];
+ Arrays.fill(parent, -1);
+ Queue q = new ArrayDeque<>();
+ q.add(s);
+ parent[s] = s;
+ while (!q.isEmpty()) {
+ int u = q.poll();
+ if (u == t) {
+ break;
+ }
+ for (int[] e : g.get(u)) {
+ int v = e[0];
+ int w = e[1];
+ if (parent[v] == -1) {
+ parent[v] = u;
+ edgeW[v] = w;
+ q.add(v);
+ }
+ }
+ }
+ int cur = t;
+ int ans = Integer.MAX_VALUE;
+ while (cur != s) {
+ ans = Math.min(ans, edgeW[cur]);
+ cur = parent[cur];
+ }
+ return ans == Integer.MAX_VALUE ? 0 : ans;
+ }
+}
From a9ba87c4b6efc77f8444fdc94de26af3c6f67df2 Mon Sep 17 00:00:00 2001
From: Taranjeet Singh Kalsi
Date: Fri, 28 Nov 2025 14:21:28 +0530
Subject: [PATCH 183/272] Added program to check Abundant number (#6961)
added program for abundant number
---
.../thealgorithms/maths/AbundantNumber.java | 58 +++++++++++++++++++
.../maths/AbundantNumberTest.java | 31 ++++++++++
2 files changed, 89 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/maths/AbundantNumber.java
create mode 100644 src/test/java/com/thealgorithms/maths/AbundantNumberTest.java
diff --git a/src/main/java/com/thealgorithms/maths/AbundantNumber.java b/src/main/java/com/thealgorithms/maths/AbundantNumber.java
new file mode 100644
index 000000000000..804ac4d71477
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/AbundantNumber.java
@@ -0,0 +1,58 @@
+package com.thealgorithms.maths;
+
+/**
+ * In number theory, an abundant number or excessive number is a positive integer for which
+ * the sum of its proper divisors is greater than the number.
+ * Equivalently, it is a number for which the sum of proper divisors (or aliquot sum) is greater than n.
+ *
+ * The integer 12 is the first abundant number. Its proper divisors are 1, 2, 3, 4 and 6 for a total of 16.
+ *
+ * Wiki: https://en.wikipedia.org/wiki/Abundant_number
+ */
+public final class AbundantNumber {
+
+ private AbundantNumber() {
+ }
+
+ // Function to calculate sum of all divisors including n
+ private static int sumOfDivisors(int n) {
+ int sum = 1 + n; // 1 and n are always divisors
+ for (int i = 2; i <= n / 2; i++) {
+ if (n % i == 0) {
+ sum += i; // adding divisor to sum
+ }
+ }
+ return sum;
+ }
+
+ // Common validation method
+ private static void validatePositiveNumber(int number) {
+ if (number <= 0) {
+ throw new IllegalArgumentException("Number must be positive.");
+ }
+ }
+
+ /**
+ * Check if {@code number} is an Abundant number or not by checking sum of divisors > 2n
+ *
+ * @param number the number
+ * @return {@code true} if {@code number} is an Abundant number, otherwise false
+ */
+ public static boolean isAbundant(int number) {
+ validatePositiveNumber(number);
+
+ return sumOfDivisors(number) > 2 * number;
+ }
+
+ /**
+ * Check if {@code number} is an Abundant number or not by checking Aliquot Sum > n
+ *
+ * @param number the number
+ * @return {@code true} if {@code number} is a Abundant number, otherwise false
+ */
+ public static boolean isAbundantNumber(int number) {
+ validatePositiveNumber(number);
+
+ return AliquotSum.getAliquotSum(number) > number;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/maths/AbundantNumberTest.java b/src/test/java/com/thealgorithms/maths/AbundantNumberTest.java
new file mode 100644
index 000000000000..5b35345afd02
--- /dev/null
+++ b/src/test/java/com/thealgorithms/maths/AbundantNumberTest.java
@@ -0,0 +1,31 @@
+package com.thealgorithms.maths;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+class AbundantNumberTest {
+ @ParameterizedTest
+ @CsvSource({"12", "66", "222", "444", "888", "2424"})
+ void abundantNumbersTest(int n) {
+ assertTrue(AbundantNumber.isAbundant(n));
+ assertTrue(AbundantNumber.isAbundantNumber(n));
+ }
+
+ @ParameterizedTest
+ @CsvSource({"1", "2", "6", "111", "333", "2222"})
+ void nonAbundantNumbersTest(int n) {
+ assertFalse(AbundantNumber.isAbundant(n));
+ assertFalse(AbundantNumber.isAbundantNumber(n));
+ }
+
+ @ParameterizedTest
+ @CsvSource({"0", "-1"})
+ void throwsNegativeNumbersNotAllowed(int n) {
+ assertThrows(IllegalArgumentException.class, () -> AbundantNumber.isAbundant(n));
+ assertThrows(IllegalArgumentException.class, () -> AbundantNumber.isAbundantNumber(n));
+ }
+}
From ac6fef19dc1a689f8e16a8a7361d1868c2c69e83 Mon Sep 17 00:00:00 2001
From: Taranjeet Singh Kalsi
Date: Mon, 1 Dec 2025 04:07:41 +0530
Subject: [PATCH 184/272] Added program to check either number is Evil or
Odious (#6958)
added program for evil number
---
.../com/thealgorithms/maths/EvilNumber.java | 39 +++++++++++++++++++
.../thealgorithms/maths/EvilNumberTest.java | 28 +++++++++++++
2 files changed, 67 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/maths/EvilNumber.java
create mode 100644 src/test/java/com/thealgorithms/maths/EvilNumberTest.java
diff --git a/src/main/java/com/thealgorithms/maths/EvilNumber.java b/src/main/java/com/thealgorithms/maths/EvilNumber.java
new file mode 100644
index 000000000000..419133702fd4
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/EvilNumber.java
@@ -0,0 +1,39 @@
+package com.thealgorithms.maths;
+
+/**
+ * In number theory, an evil number is a non-negative integer that has an even number of 1s in its binary expansion.
+ * Non-negative integers that are not evil are called odious numbers.
+ *
+ * Evil Number Wiki: https://en.wikipedia.org/wiki/Evil_number
+ * Odious Number Wiki: https://en.wikipedia.org/wiki/Odious_number
+ */
+public final class EvilNumber {
+
+ private EvilNumber() {
+ }
+
+ // Function to count number of one bits in a number using bitwise operators
+ private static int countOneBits(int number) {
+ int oneBitCounter = 0;
+ while (number > 0) {
+ oneBitCounter += number & 1; // increment count if last bit is 1
+ number >>= 1; // right shift to next bit
+ }
+ return oneBitCounter;
+ }
+
+ /**
+ * Check either {@code number} is an Evil number or Odious number
+ *
+ * @param number the number
+ * @return {@code true} if {@code number} is an Evil number, otherwise false (in case of of Odious number)
+ */
+ public static boolean isEvilNumber(int number) {
+ if (number < 0) {
+ throw new IllegalArgumentException("Negative numbers are not allowed.");
+ }
+
+ int noOfOneBits = countOneBits(number);
+ return noOfOneBits % 2 == 0;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/maths/EvilNumberTest.java b/src/test/java/com/thealgorithms/maths/EvilNumberTest.java
new file mode 100644
index 000000000000..e59171fad25f
--- /dev/null
+++ b/src/test/java/com/thealgorithms/maths/EvilNumberTest.java
@@ -0,0 +1,28 @@
+package com.thealgorithms.maths;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+class EvilNumberTest {
+ @ParameterizedTest
+ @CsvSource({"0", "3", "10", "129", "222", "500", "777", "1198"})
+ void evilNumbersTest(int n) {
+ assertTrue(EvilNumber.isEvilNumber(n));
+ }
+
+ @ParameterizedTest
+ @CsvSource({"1", "7", "100", "333", "555", "1199"})
+ void odiousNumbersTest(int n) {
+ assertFalse(EvilNumber.isEvilNumber(n));
+ }
+
+ @ParameterizedTest
+ @CsvSource({"-1"})
+ void throwsNegativeNumbersNotAllowed(int n) {
+ assertThrows(IllegalArgumentException.class, () -> EvilNumber.isEvilNumber(n));
+ }
+}
From 14c0b0844e747e3c4a9b84e8a63b6db3f6f0294d Mon Sep 17 00:00:00 2001
From: Shewale Gopal Sanjay
Date: Tue, 2 Dec 2025 01:43:14 +0530
Subject: [PATCH 185/272] Added threaded binary tree (#6995)
* Add One-Time Pad Cipher implementation in Java
* Add One-Time Pad Cipher implementation (fixed)
* Add ThreadedBinaryTree with in-order traversal and tests
* feat: add threaded binary tree implementation and tests
* fix: remove redundant null check for SpotBugs compliance
---
.../trees/ThreadedBinaryTree.java | 145 ++++++++++++++++++
.../trees/ThreadedBinaryTreeTest.java | 50 ++++++
2 files changed, 195 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTree.java
create mode 100644 src/test/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTreeTest.java
diff --git a/src/main/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTree.java b/src/main/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTree.java
new file mode 100644
index 000000000000..fd8876cecb70
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTree.java
@@ -0,0 +1,145 @@
+/*
+ * TheAlgorithms (https://github.com/TheAlgorithms/Java)
+ * Author: Shewale41
+ * This file is licensed under the MIT License.
+ */
+
+package com.thealgorithms.datastructures.trees;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Threaded binary tree implementation that supports insertion and
+ * in-order traversal without recursion or stack by using threads.
+ *
+ * In this implementation, a node's null left/right pointers are used
+ * to point to the in-order predecessor/successor respectively. Two flags
+ * indicate whether left/right pointers are real children or threads.
+ *
+ * @see Wikipedia:
+ * Threaded binary tree
+ */
+public final class ThreadedBinaryTree {
+
+ private Node root;
+
+ private static final class Node {
+ int value;
+ Node left;
+ Node right;
+ boolean leftIsThread;
+ boolean rightIsThread;
+
+ Node(int value) {
+ this.value = value;
+ this.left = null;
+ this.right = null;
+ this.leftIsThread = false;
+ this.rightIsThread = false;
+ }
+ }
+
+ public ThreadedBinaryTree() {
+ this.root = null;
+ }
+
+ /**
+ * Inserts a value into the threaded binary tree. Duplicate values are inserted
+ * to the right subtree (consistent deterministic rule).
+ *
+ * @param value the integer value to insert
+ */
+ public void insert(int value) {
+ Node newNode = new Node(value);
+ if (root == null) {
+ root = newNode;
+ return;
+ }
+
+ Node current = root;
+ Node parent = null;
+
+ while (true) {
+ parent = current;
+ if (value < current.value) {
+ if (!current.leftIsThread && current.left != null) {
+ current = current.left;
+ } else {
+ break;
+ }
+ } else { // value >= current.value
+ if (!current.rightIsThread && current.right != null) {
+ current = current.right;
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (value < parent.value) {
+ // attach newNode as left child
+ newNode.left = parent.left;
+ newNode.leftIsThread = parent.leftIsThread;
+ newNode.right = parent;
+ newNode.rightIsThread = true;
+
+ parent.left = newNode;
+ parent.leftIsThread = false;
+ } else {
+ // attach newNode as right child
+ newNode.right = parent.right;
+ newNode.rightIsThread = parent.rightIsThread;
+ newNode.left = parent;
+ newNode.leftIsThread = true;
+
+ parent.right = newNode;
+ parent.rightIsThread = false;
+ }
+ }
+
+ /**
+ * Returns the in-order traversal of the tree as a list of integers.
+ * Traversal is done without recursion or an explicit stack by following threads.
+ *
+ * @return list containing the in-order sequence of node values
+ */
+ public List inorderTraversal() {
+ List result = new ArrayList<>();
+ Node current = root;
+ if (current == null) {
+ return result;
+ }
+
+ // Move to the leftmost node
+ while (current.left != null && !current.leftIsThread) {
+ current = current.left;
+ }
+
+ while (current != null) {
+ result.add(current.value);
+
+ // If right pointer is a thread, follow it
+ if (current.rightIsThread) {
+ current = current.right;
+ } else {
+ // Move to leftmost node in right subtree
+ current = current.right;
+ while (current != null && !current.leftIsThread && current.left != null) {
+ current = current.left;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Helper: checks whether the tree is empty.
+ *
+ * @return true if tree has no nodes
+ */
+ public boolean isEmpty() {
+ return root == null;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTreeTest.java b/src/test/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTreeTest.java
new file mode 100644
index 000000000000..c5973168438e
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTreeTest.java
@@ -0,0 +1,50 @@
+/*
+ * TheAlgorithms (https://github.com/TheAlgorithms/Java)
+ * Author: Shewale41
+ * This file is licensed under the MIT License.
+ */
+
+package com.thealgorithms.datastructures.trees;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Basic tests for ThreadedBinaryTree inorder traversal.
+ */
+public class ThreadedBinaryTreeTest {
+
+ @Test
+ public void testInorderTraversalSimple() {
+ ThreadedBinaryTree tree = new ThreadedBinaryTree();
+ tree.insert(50);
+ tree.insert(30);
+ tree.insert(70);
+ tree.insert(20);
+ tree.insert(40);
+ tree.insert(60);
+ tree.insert(80);
+
+ List expected = List.of(20, 30, 40, 50, 60, 70, 80);
+ List actual = tree.inorderTraversal();
+
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testInorderWithDuplicates() {
+ ThreadedBinaryTree tree = new ThreadedBinaryTree();
+ tree.insert(5);
+ tree.insert(3);
+ tree.insert(7);
+ tree.insert(7); // duplicate
+ tree.insert(2);
+
+ List expected = List.of(2, 3, 5, 7, 7);
+ List actual = tree.inorderTraversal();
+
+ assertEquals(expected, actual);
+ }
+}
From 8d2cdb27db3b0979d28bbb2a723fa2e235a736b2 Mon Sep 17 00:00:00 2001
From: duvvuvenkataramana
Date: Tue, 2 Dec 2025 01:47:32 +0530
Subject: [PATCH 186/272] feat: implement One-Time Pad cipher (#6941) (#7096)
* feat: implement One-Time Pad cipher (#6941)
* style: format OneTimePadCipher with clang-format
---
.../ciphers/OneTimePadCipher.java | 89 +++++++++++++++++++
.../ciphers/OneTimePadCipherTest.java | 49 ++++++++++
2 files changed, 138 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/ciphers/OneTimePadCipher.java
create mode 100644 src/test/java/com/thealgorithms/ciphers/OneTimePadCipherTest.java
diff --git a/src/main/java/com/thealgorithms/ciphers/OneTimePadCipher.java b/src/main/java/com/thealgorithms/ciphers/OneTimePadCipher.java
new file mode 100644
index 000000000000..7733f5cb46f2
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/OneTimePadCipher.java
@@ -0,0 +1,89 @@
+package com.thealgorithms.ciphers;
+
+import java.security.SecureRandom;
+import java.util.Objects;
+
+/**
+ * One-Time Pad (OTP) cipher implementation.
+ *
+ * The One-Time Pad is information-theoretically secure if:
+ *
+ * - The key is truly random.
+ * - The key length is at least as long as the plaintext.
+ * - The key is used only once and kept secret.
+ *
+ *
+ * This implementation is for educational purposes only and should not be
+ * used in production systems.
+ */
+public final class OneTimePadCipher {
+
+ private static final SecureRandom RANDOM = new SecureRandom();
+
+ private OneTimePadCipher() {
+ // utility class
+ }
+
+ /**
+ * Generates a random key of the given length in bytes.
+ *
+ * @param length the length of the key in bytes, must be non-negative
+ * @return a new random key
+ * @throws IllegalArgumentException if length is negative
+ */
+ public static byte[] generateKey(int length) {
+ if (length < 0) {
+ throw new IllegalArgumentException("length must be non-negative");
+ }
+ byte[] key = new byte[length];
+ RANDOM.nextBytes(key);
+ return key;
+ }
+
+ /**
+ * Encrypts the given plaintext bytes using the provided key.
+ *
The key length must be exactly the same as the plaintext length.
+ *
+ * @param plaintext the plaintext bytes, must not be {@code null}
+ * @param key the one-time pad key bytes, must not be {@code null}
+ * @return the ciphertext bytes
+ * @throws IllegalArgumentException if the key length does not match plaintext length
+ * @throws NullPointerException if plaintext or key is {@code null}
+ */
+ public static byte[] encrypt(byte[] plaintext, byte[] key) {
+ validateInputs(plaintext, key);
+ return xor(plaintext, key);
+ }
+
+ /**
+ * Decrypts the given ciphertext bytes using the provided key.
+ *
For a One-Time Pad, decryption is identical to encryption:
+ * {@code plaintext = ciphertext XOR key}.
+ *
+ * @param ciphertext the ciphertext bytes, must not be {@code null}
+ * @param key the one-time pad key bytes, must not be {@code null}
+ * @return the decrypted plaintext bytes
+ * @throws IllegalArgumentException if the key length does not match ciphertext length
+ * @throws NullPointerException if ciphertext or key is {@code null}
+ */
+ public static byte[] decrypt(byte[] ciphertext, byte[] key) {
+ validateInputs(ciphertext, key);
+ return xor(ciphertext, key);
+ }
+
+ private static void validateInputs(byte[] input, byte[] key) {
+ Objects.requireNonNull(input, "input must not be null");
+ Objects.requireNonNull(key, "key must not be null");
+ if (input.length != key.length) {
+ throw new IllegalArgumentException("Key length must match input length");
+ }
+ }
+
+ private static byte[] xor(byte[] data, byte[] key) {
+ byte[] result = new byte[data.length];
+ for (int i = 0; i < data.length; i++) {
+ result[i] = (byte) (data[i] ^ key[i]);
+ }
+ return result;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/ciphers/OneTimePadCipherTest.java b/src/test/java/com/thealgorithms/ciphers/OneTimePadCipherTest.java
new file mode 100644
index 000000000000..837c56c603d4
--- /dev/null
+++ b/src/test/java/com/thealgorithms/ciphers/OneTimePadCipherTest.java
@@ -0,0 +1,49 @@
+package com.thealgorithms.ciphers;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.nio.charset.StandardCharsets;
+import org.junit.jupiter.api.Test;
+
+class OneTimePadCipherTest {
+
+ @Test
+ void encryptAndDecryptWithRandomKeyRestoresPlaintext() {
+ String plaintext = "The quick brown fox jumps over the lazy dog.";
+ byte[] plaintextBytes = plaintext.getBytes(StandardCharsets.UTF_8);
+
+ byte[] key = OneTimePadCipher.generateKey(plaintextBytes.length);
+
+ byte[] ciphertext = OneTimePadCipher.encrypt(plaintextBytes, key);
+ byte[] decrypted = OneTimePadCipher.decrypt(ciphertext, key);
+
+ assertArrayEquals(plaintextBytes, decrypted);
+ assertEquals(plaintext, new String(decrypted, StandardCharsets.UTF_8));
+ }
+
+ @Test
+ void generateKeyWithNegativeLengthThrowsException() {
+ assertThrows(IllegalArgumentException.class, () -> OneTimePadCipher.generateKey(-1));
+ }
+
+ @Test
+ void encryptWithMismatchedKeyLengthThrowsException() {
+ byte[] data = "hello".getBytes(StandardCharsets.UTF_8);
+ byte[] shortKey = OneTimePadCipher.generateKey(2);
+
+ assertThrows(IllegalArgumentException.class, () -> OneTimePadCipher.encrypt(data, shortKey));
+ }
+
+ @Test
+ void decryptWithMismatchedKeyLengthThrowsException() {
+ byte[] data = "hello".getBytes(StandardCharsets.UTF_8);
+ byte[] key = OneTimePadCipher.generateKey(data.length);
+ byte[] ciphertext = OneTimePadCipher.encrypt(data, key);
+
+ byte[] wrongSizedKey = OneTimePadCipher.generateKey(data.length + 1);
+
+ assertThrows(IllegalArgumentException.class, () -> OneTimePadCipher.decrypt(ciphertext, wrongSizedKey));
+ }
+}
From 927fe1f87cdfe2ea57051812427e78c9cf6f4775 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 2 Dec 2025 09:54:59 +0100
Subject: [PATCH 187/272] chore(deps): bump com.puppycrawl.tools:checkstyle
from 12.1.2 to 12.2.0 (#7147)
Bumps [com.puppycrawl.tools:checkstyle](https://github.com/checkstyle/checkstyle) from 12.1.2 to 12.2.0.
- [Release notes](https://github.com/checkstyle/checkstyle/releases)
- [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-12.1.2...checkstyle-12.2.0)
---
updated-dependencies:
- dependency-name: com.puppycrawl.tools:checkstyle
dependency-version: 12.2.0
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 6b918cdad5bb..dc7d211b2742 100644
--- a/pom.xml
+++ b/pom.xml
@@ -112,7 +112,7 @@
com.puppycrawl.tools
checkstyle
- 12.1.2
+ 12.2.0
From bd7f269aa992e87359d82b3d3d289b4fefde5eea Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 2 Dec 2025 08:58:42 +0000
Subject: [PATCH 188/272] chore(deps): bump gitpod/workspace-java-21 from
2025-10-06-13-14-25 to 2025-11-14-10-05-32 (#7148)
chore(deps): bump gitpod/workspace-java-21
Bumps gitpod/workspace-java-21 from 2025-10-06-13-14-25 to 2025-11-14-10-05-32.
---
updated-dependencies:
- dependency-name: gitpod/workspace-java-21
dependency-version: 2025-11-14-10-05-32
dependency-type: direct:production
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.gitpod.dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.gitpod.dockerfile b/.gitpod.dockerfile
index 4195f928d1bc..a8951da7de26 100644
--- a/.gitpod.dockerfile
+++ b/.gitpod.dockerfile
@@ -1,4 +1,4 @@
-FROM gitpod/workspace-java-21:2025-10-06-13-14-25
+FROM gitpod/workspace-java-21:2025-11-14-10-05-32
ENV LLVM_SCRIPT="tmp_llvm.sh"
From 246162e5bdc6b9f4eb4cf8287e31eb44c36301da Mon Sep 17 00:00:00 2001
From: espinosadev <163946778+espinosa-dev@users.noreply.github.com>
Date: Fri, 5 Dec 2025 16:45:25 +0100
Subject: [PATCH 189/272] Fixed redundant boolean logic (#7151)
---
.../java/com/thealgorithms/strings/Upper.java | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/src/main/java/com/thealgorithms/strings/Upper.java b/src/main/java/com/thealgorithms/strings/Upper.java
index 5e248cb6ee39..85db7d41e1aa 100644
--- a/src/main/java/com/thealgorithms/strings/Upper.java
+++ b/src/main/java/com/thealgorithms/strings/Upper.java
@@ -15,23 +15,27 @@ public static void main(String[] args) {
}
/**
- * Converts all the characters in this {@code String} to upper case
+ * Converts all the characters in this {@code String} to upper case.
*
* @param s the string to convert
* @return the {@code String}, converted to uppercase.
*/
public static String toUpperCase(String s) {
if (s == null) {
- throw new IllegalArgumentException("Input string connot be null");
+ throw new IllegalArgumentException("Input string cannot be null");
}
if (s.isEmpty()) {
return s;
}
- StringBuilder result = new StringBuilder(s);
- for (int i = 0; i < result.length(); ++i) {
- char currentChar = result.charAt(i);
- if (Character.isLetter(currentChar) && Character.isLowerCase(currentChar)) {
- result.setCharAt(i, Character.toUpperCase(currentChar));
+
+ StringBuilder result = new StringBuilder(s.length());
+
+ for (int i = 0; i < s.length(); ++i) {
+ char currentChar = s.charAt(i);
+ if (Character.isLowerCase(currentChar)) {
+ result.append(Character.toUpperCase(currentChar));
+ } else {
+ result.append(currentChar);
}
}
return result.toString();
From 316def4ea65f68ca8982148b97896c8bfef27e87 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20S=C3=A1nchez=20N=C3=BA=C3=B1ez?=
Date: Sun, 7 Dec 2025 12:18:55 +0100
Subject: [PATCH 190/272] Add Snell's Law refraction algorithm (#7150)
* Add Snell's Law implementation for refraction angle
* Add tests for Snell's Law calculations
* Update documentation with reference link to Snell's Law
Added a reference link to Snell's Law in the documentation.
* Prevent instantiation of SnellLaw class
Make SnellLaw class non-instantiable by adding a private constructor.
* Rename SnellsLawTest to SnellLawTest
* Refactor SnellLawTest for clarity and accuracy
* Rename SnellsLaw.java to SnellLaw.java
* Refactor SnellLawTest with additional assertions
* Refactor SnellLaw class constructor and error handling
Refactor SnellLaw constructor and error message formatting.
* Fix missing newline at end of SnellLawTest.java
Ensure that the SnellLawTest class has a newline at the end of the file.
* Simplify assertions in SnellLawTest
* Simplify exception throwing for total internal reflection
---
.../com/thealgorithms/physics/SnellLaw.java | 33 +++++++++++++++
.../thealgorithms/physics/SnellLawTest.java | 41 +++++++++++++++++++
2 files changed, 74 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/physics/SnellLaw.java
create mode 100644 src/test/java/com/thealgorithms/physics/SnellLawTest.java
diff --git a/src/main/java/com/thealgorithms/physics/SnellLaw.java b/src/main/java/com/thealgorithms/physics/SnellLaw.java
new file mode 100644
index 000000000000..2736984814fd
--- /dev/null
+++ b/src/main/java/com/thealgorithms/physics/SnellLaw.java
@@ -0,0 +1,33 @@
+package com.thealgorithms.physics;
+
+/**
+ * Calculates refraction angle using Snell's Law:
+ * n1 * sin(theta1) = n2 * sin(theta2)
+ * @see Snell's Law
+ */
+public final class SnellLaw {
+
+ private SnellLaw() {
+ throw new AssertionError("No instances.");
+ }
+
+ /**
+ * Computes the refracted angle (theta2) in radians.
+ *
+ * @param n1 index of refraction of medium 1
+ * @param n2 index of refraction of medium 2
+ * @param theta1 incident angle in radians
+ * @return refracted angle (theta2) in radians
+ * @throws IllegalArgumentException if total internal reflection occurs
+ */
+ public static double refractedAngle(double n1, double n2, double theta1) {
+ double ratio = n1 / n2;
+ double sinTheta2 = ratio * Math.sin(theta1);
+
+ if (Math.abs(sinTheta2) > 1.0) {
+ throw new IllegalArgumentException("Total internal reflection: no refraction possible.");
+ }
+
+ return Math.asin(sinTheta2);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/physics/SnellLawTest.java b/src/test/java/com/thealgorithms/physics/SnellLawTest.java
new file mode 100644
index 000000000000..ddd5fb1d5af7
--- /dev/null
+++ b/src/test/java/com/thealgorithms/physics/SnellLawTest.java
@@ -0,0 +1,41 @@
+package com.thealgorithms.physics;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class SnellLawTest {
+
+ @Test
+ public void testRefractedAngle() {
+ double n1 = 1.0; // air
+ double n2 = 1.5; // glass
+ double theta1 = Math.toRadians(30);
+
+ double theta2 = SnellLaw.refractedAngle(n1, n2, theta1);
+
+ double expected = Math.asin(n1 / n2 * Math.sin(theta1));
+
+ assertEquals(expected, theta2, 1e-12);
+ }
+
+ @Test
+ public void testTotalInternalReflection() {
+ double n1 = 1.5;
+ double n2 = 1.0;
+ double theta1 = Math.toRadians(60); // large angle
+
+ assertThrows(IllegalArgumentException.class, () -> SnellLaw.refractedAngle(n1, n2, theta1));
+ }
+
+ @Test
+ public void testNoTotalInternalReflectionAtLowAngles() {
+ double n1 = 1.5;
+ double n2 = 1.0;
+ double theta1 = Math.toRadians(10);
+
+ assertDoesNotThrow(() -> SnellLaw.refractedAngle(n1, n2, theta1));
+ }
+}
From e7c3e1f7739a494d96ded480b167b28ca657f1cc Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 9 Dec 2025 09:43:17 +0100
Subject: [PATCH 191/272] chore(deps): bump
com.mebigfatguy.fb-contrib:fb-contrib from 7.7.1 to 7.7.2 (#7153)
chore(deps): bump com.mebigfatguy.fb-contrib:fb-contrib
Bumps [com.mebigfatguy.fb-contrib:fb-contrib](https://github.com/mebigfatguy/fb-contrib) from 7.7.1 to 7.7.2.
- [Commits](https://github.com/mebigfatguy/fb-contrib/commits/v7.7.2)
---
updated-dependencies:
- dependency-name: com.mebigfatguy.fb-contrib:fb-contrib
dependency-version: 7.7.2
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index dc7d211b2742..4baf7a5f99b0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -127,7 +127,7 @@
com.mebigfatguy.fb-contrib
fb-contrib
- 7.7.1
+ 7.7.2
com.h3xstream.findsecbugs
From 520151ab8e51b502e96cd959ebdfdfff7468aa22 Mon Sep 17 00:00:00 2001
From: codeahl <142953446+codeahl@users.noreply.github.com>
Date: Wed, 10 Dec 2025 03:00:28 -0600
Subject: [PATCH 192/272] Add Big-O time and space complexity comments for
sorting algorithms (#7155)
Add time and space complexity comments for specific sorting algorithms
Co-authored-by: Deniz Altunkapan
---
.../com/thealgorithms/sorts/BubbleSort.java | 7 +++++++
.../java/com/thealgorithms/sorts/HeapSort.java | 13 ++++++++++++-
.../com/thealgorithms/sorts/InsertionSort.java | 18 ++++++++++++++++++
.../com/thealgorithms/sorts/MergeSort.java | 13 +++++++++----
.../com/thealgorithms/sorts/QuickSort.java | 11 +++++++++--
.../com/thealgorithms/sorts/SelectionSort.java | 13 +++++++++----
.../thealgorithms/sorts/TopologicalSort.java | 11 +++++++++--
7 files changed, 73 insertions(+), 13 deletions(-)
diff --git a/src/main/java/com/thealgorithms/sorts/BubbleSort.java b/src/main/java/com/thealgorithms/sorts/BubbleSort.java
index 6823c68d0a74..d2eca3506c2d 100644
--- a/src/main/java/com/thealgorithms/sorts/BubbleSort.java
+++ b/src/main/java/com/thealgorithms/sorts/BubbleSort.java
@@ -10,6 +10,13 @@ class BubbleSort implements SortAlgorithm {
/**
* Implements generic bubble sort algorithm.
*
+ * Time Complexity:
+ * - Best case: O(n) – array is already sorted.
+ * - Average case: O(n^2)
+ * - Worst case: O(n^2)
+ *
+ * Space Complexity: O(1) – in-place sorting.
+ *
* @param array the array to be sorted.
* @param the type of elements in the array.
* @return the sorted array.
diff --git a/src/main/java/com/thealgorithms/sorts/HeapSort.java b/src/main/java/com/thealgorithms/sorts/HeapSort.java
index e798fb91b925..5e3b20f43e10 100644
--- a/src/main/java/com/thealgorithms/sorts/HeapSort.java
+++ b/src/main/java/com/thealgorithms/sorts/HeapSort.java
@@ -1,9 +1,20 @@
package com.thealgorithms.sorts;
/**
- * Heap Sort Algorithm Implementation
+ * Heap Sort algorithm implementation.
+ *
+ * Heap sort converts the array into a max-heap and repeatedly extracts the maximum
+ * element to sort the array in increasing order.
+ *
+ * Time Complexity:
+ * - Best case: O(n log n)
+ * - Average case: O(n log n)
+ * - Worst case: O(n log n)
+ *
+ * Space Complexity: O(1) – in-place sorting
*
* @see Heap Sort Algorithm
+ * @see SortAlgorithm
*/
public class HeapSort implements SortAlgorithm {
diff --git a/src/main/java/com/thealgorithms/sorts/InsertionSort.java b/src/main/java/com/thealgorithms/sorts/InsertionSort.java
index 21ebf3827b5f..fdbfd9cd1cfa 100644
--- a/src/main/java/com/thealgorithms/sorts/InsertionSort.java
+++ b/src/main/java/com/thealgorithms/sorts/InsertionSort.java
@@ -1,5 +1,23 @@
package com.thealgorithms.sorts;
+/**
+ * Generic Insertion Sort algorithm.
+ *
+ * Standard insertion sort iterates through the array and inserts each element into its
+ * correct position in the sorted portion of the array.
+ *
+ * Sentinel sort is a variation that first places the minimum element at index 0 to
+ * avoid redundant comparisons in subsequent passes.
+ *
+ * Time Complexity:
+ * - Best case: O(n) – array is already sorted (sentinel sort can improve slightly)
+ * - Average case: O(n^2)
+ * - Worst case: O(n^2) – array is reverse sorted
+ *
+ * Space Complexity: O(1) – in-place sorting
+ *
+ * @see SortAlgorithm
+ */
class InsertionSort implements SortAlgorithm {
/**
diff --git a/src/main/java/com/thealgorithms/sorts/MergeSort.java b/src/main/java/com/thealgorithms/sorts/MergeSort.java
index 86a184f67b26..f7a7c8da004d 100644
--- a/src/main/java/com/thealgorithms/sorts/MergeSort.java
+++ b/src/main/java/com/thealgorithms/sorts/MergeSort.java
@@ -13,11 +13,16 @@ class MergeSort implements SortAlgorithm {
private Comparable[] aux;
/**
- * Generic merge sort algorithm implements.
+ * Generic merge sort algorithm.
*
- * @param unsorted the array which should be sorted.
- * @param Comparable class.
- * @return sorted array.
+ * Time Complexity:
+ * - Best case: O(n log n)
+ * - Average case: O(n log n)
+ * - Worst case: O(n log n)
+ *
+ * Space Complexity: O(n) – requires auxiliary array for merging.
+ *
+ * @see SortAlgorithm
*/
@Override
public > T[] sort(T[] unsorted) {
diff --git a/src/main/java/com/thealgorithms/sorts/QuickSort.java b/src/main/java/com/thealgorithms/sorts/QuickSort.java
index 3abb1aae2306..a025e6909259 100644
--- a/src/main/java/com/thealgorithms/sorts/QuickSort.java
+++ b/src/main/java/com/thealgorithms/sorts/QuickSort.java
@@ -8,9 +8,16 @@
class QuickSort implements SortAlgorithm {
/**
- * This method implements the Generic Quick Sort
+ * Generic Quick Sort algorithm.
*
- * @param array The array to be sorted Sorts the array in increasing order
+ * Time Complexity:
+ * - Best case: O(n log n) – pivot splits array roughly in half each time.
+ * - Average case: O(n log n)
+ * - Worst case: O(n^2) – occurs when pivot consistently produces unbalanced splits.
+ *
+ * Space Complexity: O(log n) – recursion stack, in-place sorting.
+ *
+ * @see SortAlgorithm
*/
@Override
public > T[] sort(T[] array) {
diff --git a/src/main/java/com/thealgorithms/sorts/SelectionSort.java b/src/main/java/com/thealgorithms/sorts/SelectionSort.java
index db7732d7e218..2d1814441701 100644
--- a/src/main/java/com/thealgorithms/sorts/SelectionSort.java
+++ b/src/main/java/com/thealgorithms/sorts/SelectionSort.java
@@ -2,11 +2,16 @@
public class SelectionSort implements SortAlgorithm {
/**
- * Sorts an array of comparable elements in increasing order using the selection sort algorithm.
+ * Generic Selection Sort algorithm.
*
- * @param array the array to be sorted
- * @param the class of array elements
- * @return the sorted array
+ * Time Complexity:
+ * - Best case: O(n^2)
+ * - Average case: O(n^2)
+ * - Worst case: O(n^2)
+ *
+ * Space Complexity: O(1) – in-place sorting.
+ *
+ * @see SortAlgorithm
*/
@Override
public > T[] sort(T[] array) {
diff --git a/src/main/java/com/thealgorithms/sorts/TopologicalSort.java b/src/main/java/com/thealgorithms/sorts/TopologicalSort.java
index e4ed240a9947..382ddde9a6f2 100644
--- a/src/main/java/com/thealgorithms/sorts/TopologicalSort.java
+++ b/src/main/java/com/thealgorithms/sorts/TopologicalSort.java
@@ -11,9 +11,16 @@
* a linked list. A Directed Graph is proven to be acyclic when a DFS or Depth First Search is
* performed, yielding no back-edges.
*
- * https://en.wikipedia.org/wiki/Topological_sorting
+ * Time Complexity: O(V + E)
+ * - V: number of vertices
+ * - E: number of edges
*
- * @author Jonathan Taylor (https://github.com/Jtmonument)
+ * Space Complexity: O(V + E)
+ * - adjacency list and recursion stack in DFS
+ *
+ * Reference: https://en.wikipedia.org/wiki/Topological_sorting
+ *
+ * Author: Jonathan Taylor (https://github.com/Jtmonument)
* Based on Introduction to Algorithms 3rd Edition
*/
public final class TopologicalSort {
From 4f40206684b026f8c0315d8fa419f4951e0500ba Mon Sep 17 00:00:00 2001
From: Lucas Horn <146038502+LucasAHorn@users.noreply.github.com>
Date: Wed, 10 Dec 2025 03:04:32 -0600
Subject: [PATCH 193/272] Add unit tests for graph algorithms (#7133) (#7156)
* Add unit tests for graph algorithms (BFS, DFS, Dijkstra, Bellman-Ford) #7133
- Created BellmanFordTest.java with 10 test methods covering various graph scenarios
- Created ConnectedComponentTest.java with 15 test methods for DFS-based component counting
- Enhanced MatrixGraphsTest.java with additional BFS/DFS test cases
- Enhanced DijkstraAlgorithmTest.java with comprehensive shortest path tests
Fixes #7133
* fix: format files using clang
* fix: removing my changes on pull_request_template
---------
Co-authored-by: prashantdubeypng
---
.../graphs/BellmanFordTest.java | 158 +++++++++++++
.../graphs/ConnectedComponentTest.java | 204 +++++++++++++++++
.../graphs/DijkstraAlgorithmTest.java | 117 ++++++++++
.../graphs/MatrixGraphsTest.java | 211 ++++++++++++++++++
4 files changed, 690 insertions(+)
create mode 100644 src/test/java/com/thealgorithms/datastructures/graphs/BellmanFordTest.java
create mode 100644 src/test/java/com/thealgorithms/datastructures/graphs/ConnectedComponentTest.java
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/BellmanFordTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/BellmanFordTest.java
new file mode 100644
index 000000000000..c824241c680d
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/BellmanFordTest.java
@@ -0,0 +1,158 @@
+package com.thealgorithms.datastructures.graphs;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the BellmanFord algorithm implementation.
+ * Tests cover various graph scenarios including:
+ * - Simple weighted graphs
+ * - Graphs with negative weights
+ * - Single vertex graphs
+ * - Disconnected graphs
+ * - Linear path graphs
+ */
+class BellmanFordTest {
+
+ @Test
+ void testSimpleGraph() {
+ // Create a simple graph with 5 vertices and 8 edges
+ // Graph visualization:
+ // 1
+ // /|\
+ // 6 | 7
+ // / | \
+ // 0 5 2
+ // \ | /
+ // 8 | -2
+ // \|/
+ // 4---3
+ // 9
+ BellmanFord bellmanFord = new BellmanFord(5, 8);
+ bellmanFord.addEdge(0, 1, 6);
+ bellmanFord.addEdge(0, 4, 8);
+ bellmanFord.addEdge(1, 2, 7);
+ bellmanFord.addEdge(1, 4, 5);
+ bellmanFord.addEdge(2, 3, -2);
+ bellmanFord.addEdge(2, 4, -3);
+ bellmanFord.addEdge(3, 4, 9);
+ bellmanFord.addEdge(4, 3, 7);
+
+ // Verify edge array creation
+ assertNotNull(bellmanFord.getEdgeArray());
+ assertEquals(8, bellmanFord.getEdgeArray().length);
+ }
+
+ @Test
+ void testGraphWithNegativeWeights() {
+ // Graph with negative edge weights (but no negative cycle)
+ BellmanFord bellmanFord = new BellmanFord(4, 5);
+ bellmanFord.addEdge(0, 1, 4);
+ bellmanFord.addEdge(0, 2, 5);
+ bellmanFord.addEdge(1, 2, -3);
+ bellmanFord.addEdge(2, 3, 4);
+ bellmanFord.addEdge(1, 3, 6);
+
+ assertNotNull(bellmanFord.getEdgeArray());
+ assertEquals(5, bellmanFord.getEdgeArray().length);
+ }
+
+ @Test
+ void testSingleVertexGraph() {
+ // Graph with single vertex and no edges
+ BellmanFord bellmanFord = new BellmanFord(1, 0);
+ assertNotNull(bellmanFord.getEdgeArray());
+ assertEquals(0, bellmanFord.getEdgeArray().length);
+ }
+
+ @Test
+ void testLinearGraph() {
+ // Linear graph: 0 -> 1 -> 2 -> 3
+ BellmanFord bellmanFord = new BellmanFord(4, 3);
+ bellmanFord.addEdge(0, 1, 2);
+ bellmanFord.addEdge(1, 2, 3);
+ bellmanFord.addEdge(2, 3, 4);
+
+ assertNotNull(bellmanFord.getEdgeArray());
+ assertEquals(3, bellmanFord.getEdgeArray().length);
+ }
+
+ @Test
+ void testEdgeAddition() {
+ BellmanFord bellmanFord = new BellmanFord(3, 3);
+
+ bellmanFord.addEdge(0, 1, 5);
+ bellmanFord.addEdge(1, 2, 3);
+ bellmanFord.addEdge(0, 2, 10);
+
+ // Verify all edges were added
+ assertNotNull(bellmanFord.getEdgeArray());
+ assertEquals(3, bellmanFord.getEdgeArray().length);
+ }
+
+ @Test
+ void testGraphWithZeroWeightEdges() {
+ // Graph with zero weight edges
+ BellmanFord bellmanFord = new BellmanFord(3, 3);
+ bellmanFord.addEdge(0, 1, 0);
+ bellmanFord.addEdge(1, 2, 0);
+ bellmanFord.addEdge(0, 2, 1);
+
+ assertNotNull(bellmanFord.getEdgeArray());
+ assertEquals(3, bellmanFord.getEdgeArray().length);
+ }
+
+ @Test
+ void testLargerGraph() {
+ // Larger graph with 6 vertices
+ BellmanFord bellmanFord = new BellmanFord(6, 9);
+ bellmanFord.addEdge(0, 1, 5);
+ bellmanFord.addEdge(0, 2, 3);
+ bellmanFord.addEdge(1, 3, 6);
+ bellmanFord.addEdge(1, 2, 2);
+ bellmanFord.addEdge(2, 4, 4);
+ bellmanFord.addEdge(2, 5, 2);
+ bellmanFord.addEdge(2, 3, 7);
+ bellmanFord.addEdge(3, 4, -1);
+ bellmanFord.addEdge(4, 5, -2);
+
+ assertNotNull(bellmanFord.getEdgeArray());
+ assertEquals(9, bellmanFord.getEdgeArray().length);
+ }
+
+ @Test
+ void testVertexAndEdgeCount() {
+ BellmanFord bellmanFord = new BellmanFord(10, 15);
+ assertEquals(10, bellmanFord.vertex);
+ assertEquals(15, bellmanFord.edge);
+ }
+
+ @Test
+ void testMultipleEdgesBetweenSameVertices() {
+ // Graph allowing multiple edges between same vertices
+ BellmanFord bellmanFord = new BellmanFord(2, 3);
+ bellmanFord.addEdge(0, 1, 5);
+ bellmanFord.addEdge(0, 1, 3);
+ bellmanFord.addEdge(1, 0, 2);
+
+ assertNotNull(bellmanFord.getEdgeArray());
+ assertEquals(3, bellmanFord.getEdgeArray().length);
+ }
+
+ @Test
+ void testCompleteGraph() {
+ // Complete graph with 4 vertices (6 edges for undirected equivalent)
+ BellmanFord bellmanFord = new BellmanFord(4, 6);
+ bellmanFord.addEdge(0, 1, 1);
+ bellmanFord.addEdge(0, 2, 2);
+ bellmanFord.addEdge(0, 3, 3);
+ bellmanFord.addEdge(1, 2, 4);
+ bellmanFord.addEdge(1, 3, 5);
+ bellmanFord.addEdge(2, 3, 6);
+
+ assertNotNull(bellmanFord.getEdgeArray());
+ assertEquals(6, bellmanFord.getEdgeArray().length);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/ConnectedComponentTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/ConnectedComponentTest.java
new file mode 100644
index 000000000000..b5cfdd9de04f
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/ConnectedComponentTest.java
@@ -0,0 +1,204 @@
+package com.thealgorithms.datastructures.graphs;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the Graph class in ConnectedComponent.java.
+ * Tests the depth-first search implementation and connected component counting.
+ * Covers various graph topologies including:
+ * - Single connected components
+ * - Multiple disconnected components
+ * - Self-loops
+ * - Linear chains
+ * - Cyclic graphs
+ */
+class ConnectedComponentTest {
+
+ @Test
+ void testSingleConnectedComponent() {
+ Graph graph = new Graph<>();
+ graph.addEdge(1, 2);
+ graph.addEdge(2, 3);
+ graph.addEdge(3, 4);
+ graph.addEdge(4, 1);
+
+ assertEquals(1, graph.countGraphs());
+ }
+
+ @Test
+ void testTwoDisconnectedComponents() {
+ Graph graph = new Graph<>();
+ // Component 1: 1-2-3
+ graph.addEdge(1, 2);
+ graph.addEdge(2, 3);
+ // Component 2: 4-5
+ graph.addEdge(4, 5);
+
+ assertEquals(2, graph.countGraphs());
+ }
+
+ @Test
+ void testThreeDisconnectedComponents() {
+ Graph graph = new Graph<>();
+ // Component 1: a-b-c-d-e
+ graph.addEdge('a', 'b');
+ graph.addEdge('a', 'e');
+ graph.addEdge('b', 'e');
+ graph.addEdge('b', 'c');
+ graph.addEdge('c', 'd');
+ graph.addEdge('d', 'a');
+ // Component 2: x-y-z
+ graph.addEdge('x', 'y');
+ graph.addEdge('x', 'z');
+ // Component 3: w (self-loop)
+ graph.addEdge('w', 'w');
+
+ assertEquals(3, graph.countGraphs());
+ }
+
+ @Test
+ void testSingleNodeSelfLoop() {
+ Graph graph = new Graph<>();
+ graph.addEdge(1, 1);
+
+ assertEquals(1, graph.countGraphs());
+ }
+
+ @Test
+ void testLinearChain() {
+ Graph graph = new Graph<>();
+ graph.addEdge(1, 2);
+ graph.addEdge(2, 3);
+ graph.addEdge(3, 4);
+ graph.addEdge(4, 5);
+
+ assertEquals(1, graph.countGraphs());
+ }
+
+ @Test
+ void testStarTopology() {
+ // Star graph with center node 0 connected to nodes 1, 2, 3, 4
+ Graph graph = new Graph<>();
+ graph.addEdge(0, 1);
+ graph.addEdge(0, 2);
+ graph.addEdge(0, 3);
+ graph.addEdge(0, 4);
+
+ assertEquals(1, graph.countGraphs());
+ }
+
+ @Test
+ void testCompleteGraph() {
+ // Complete graph K4: every node connected to every other node
+ Graph graph = new Graph<>();
+ graph.addEdge(1, 2);
+ graph.addEdge(1, 3);
+ graph.addEdge(1, 4);
+ graph.addEdge(2, 3);
+ graph.addEdge(2, 4);
+ graph.addEdge(3, 4);
+
+ assertEquals(1, graph.countGraphs());
+ }
+
+ @Test
+ void testStringVertices() {
+ Graph graph = new Graph<>();
+ // Component 1
+ graph.addEdge("New York", "Los Angeles");
+ graph.addEdge("Los Angeles", "Chicago");
+ // Component 2
+ graph.addEdge("London", "Paris");
+ // Component 3
+ graph.addEdge("Tokyo", "Tokyo");
+
+ assertEquals(3, graph.countGraphs());
+ }
+
+ @Test
+ void testEmptyGraph() {
+ Graph graph = new Graph<>();
+ assertEquals(0, graph.countGraphs());
+ }
+
+ @Test
+ void testDepthFirstSearchBasic() {
+ Graph graph = new Graph<>();
+ graph.addEdge(1, 2);
+ graph.addEdge(2, 3);
+
+ // Get the first node and perform DFS
+ assertNotNull(graph.nodeList);
+ assertEquals(3, graph.nodeList.size());
+ }
+
+ @Test
+ void testManyIsolatedComponents() {
+ Graph graph = new Graph<>();
+ // Create 5 isolated components (each is a self-loop)
+ graph.addEdge(1, 1);
+ graph.addEdge(2, 2);
+ graph.addEdge(3, 3);
+ graph.addEdge(4, 4);
+ graph.addEdge(5, 5);
+
+ assertEquals(5, graph.countGraphs());
+ }
+
+ @Test
+ void testBidirectionalEdges() {
+ Graph graph = new Graph<>();
+ // Note: This is a directed graph representation
+ // Adding edge 1->2 does not automatically add 2->1
+ graph.addEdge(1, 2);
+ graph.addEdge(2, 1);
+ graph.addEdge(2, 3);
+ graph.addEdge(3, 2);
+
+ assertEquals(1, graph.countGraphs());
+ }
+
+ @Test
+ void testCyclicGraph() {
+ Graph graph = new Graph<>();
+ // Create a cycle: 1 -> 2 -> 3 -> 4 -> 1
+ graph.addEdge(1, 2);
+ graph.addEdge(2, 3);
+ graph.addEdge(3, 4);
+ graph.addEdge(4, 1);
+
+ assertEquals(1, graph.countGraphs());
+ }
+
+ @Test
+ void testMultipleCycles() {
+ Graph graph = new Graph<>();
+ // Cycle 1: 1 -> 2 -> 3 -> 1
+ graph.addEdge(1, 2);
+ graph.addEdge(2, 3);
+ graph.addEdge(3, 1);
+ // Cycle 2: 4 -> 5 -> 4
+ graph.addEdge(4, 5);
+ graph.addEdge(5, 4);
+
+ assertEquals(2, graph.countGraphs());
+ }
+
+ @Test
+ void testIntegerGraphFromMainExample() {
+ // Recreate the example from main method
+ Graph graph = new Graph<>();
+ graph.addEdge(1, 2);
+ graph.addEdge(2, 3);
+ graph.addEdge(2, 4);
+ graph.addEdge(3, 5);
+ graph.addEdge(7, 8);
+ graph.addEdge(8, 10);
+ graph.addEdge(10, 8);
+
+ assertEquals(2, graph.countGraphs());
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java
index c5df9acdf33b..a189091c17d3 100644
--- a/src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java
@@ -1,6 +1,7 @@
package com.thealgorithms.datastructures.graphs;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.BeforeEach;
@@ -61,4 +62,120 @@ void testInvalidSourceVertex() {
assertThrows(IllegalArgumentException.class, () -> dijkstraAlgorithm.run(graph, -1));
assertThrows(IllegalArgumentException.class, () -> dijkstraAlgorithm.run(graph, graph.length));
}
+
+ @Test
+ void testLinearGraph() {
+ // Linear graph: 0 - 1 - 2 - 3
+ // with weights: 2 3 4
+ int[][] linearGraph = {{0, 2, 0, 0}, {2, 0, 3, 0}, {0, 3, 0, 4}, {0, 0, 4, 0}};
+
+ DijkstraAlgorithm dijkstraLinear = new DijkstraAlgorithm(4);
+ int[] distances = dijkstraLinear.run(linearGraph, 0);
+
+ assertArrayEquals(new int[] {0, 2, 5, 9}, distances);
+ }
+
+ @Test
+ void testStarTopology() {
+ // Star graph: center node 0 connected to all others
+ // 1(2)
+ // |
+ // 3(4)-0-2(3)
+ // |
+ // 4(5)
+ int[][] starGraph = {{0, 2, 3, 4, 5}, {2, 0, 0, 0, 0}, {3, 0, 0, 0, 0}, {4, 0, 0, 0, 0}, {5, 0, 0, 0, 0}};
+
+ DijkstraAlgorithm dijkstraStar = new DijkstraAlgorithm(5);
+ int[] distances = dijkstraStar.run(starGraph, 0);
+
+ assertArrayEquals(new int[] {0, 2, 3, 4, 5}, distances);
+ }
+
+ @Test
+ void testCompleteGraphK4() {
+ // Complete graph K4 with varying weights
+ int[][] completeGraph = {{0, 1, 2, 3}, {1, 0, 4, 5}, {2, 4, 0, 6}, {3, 5, 6, 0}};
+
+ DijkstraAlgorithm dijkstraComplete = new DijkstraAlgorithm(4);
+ int[] distances = dijkstraComplete.run(completeGraph, 0);
+
+ // Direct paths from 0 are shortest
+ assertArrayEquals(new int[] {0, 1, 2, 3}, distances);
+ }
+
+ @Test
+ void testDifferentSourceVertex() {
+ // Test running from different source vertices
+ int[][] simpleGraph = {{0, 5, 0, 0}, {5, 0, 3, 0}, {0, 3, 0, 2}, {0, 0, 2, 0}};
+
+ DijkstraAlgorithm dijkstra = new DijkstraAlgorithm(4);
+
+ // From vertex 0
+ int[] distFrom0 = dijkstra.run(simpleGraph, 0);
+ assertArrayEquals(new int[] {0, 5, 8, 10}, distFrom0);
+
+ // From vertex 2
+ int[] distFrom2 = dijkstra.run(simpleGraph, 2);
+ assertArrayEquals(new int[] {8, 3, 0, 2}, distFrom2);
+
+ // From vertex 3
+ int[] distFrom3 = dijkstra.run(simpleGraph, 3);
+ assertArrayEquals(new int[] {10, 5, 2, 0}, distFrom3);
+ }
+
+ @Test
+ void testUnitWeightGraph() {
+ // Graph with all unit weights (like BFS distance)
+ int[][] unitGraph = {{0, 1, 1, 0}, {1, 0, 1, 1}, {1, 1, 0, 1}, {0, 1, 1, 0}};
+
+ DijkstraAlgorithm dijkstraUnit = new DijkstraAlgorithm(4);
+ int[] distances = dijkstraUnit.run(unitGraph, 0);
+
+ assertArrayEquals(new int[] {0, 1, 1, 2}, distances);
+ }
+
+ @Test
+ void testTwoVertexGraph() {
+ int[][] twoVertexGraph = {{0, 7}, {7, 0}};
+
+ DijkstraAlgorithm dijkstraTwo = new DijkstraAlgorithm(2);
+ int[] distances = dijkstraTwo.run(twoVertexGraph, 0);
+
+ assertArrayEquals(new int[] {0, 7}, distances);
+ }
+
+ @Test
+ void testShortcutPath() {
+ // Graph where direct path is longer than indirect path
+ // 0 --(10)--> 2
+ // 0 --(1)--> 1 --(2)--> 2
+ int[][] shortcutGraph = {{0, 1, 10}, {1, 0, 2}, {10, 2, 0}};
+
+ DijkstraAlgorithm dijkstraShortcut = new DijkstraAlgorithm(3);
+ int[] distances = dijkstraShortcut.run(shortcutGraph, 0);
+
+ // The shortest path to vertex 2 should be 3 (via vertex 1), not 10 (direct)
+ assertArrayEquals(new int[] {0, 1, 3}, distances);
+ }
+
+ @Test
+ void testSourceToSourceDistanceIsZero() {
+ // Verify distance from source to itself is always 0
+ int[] distances = dijkstraAlgorithm.run(graph, 0);
+ assertEquals(0, distances[0]);
+
+ distances = dijkstraAlgorithm.run(graph, 5);
+ assertEquals(0, distances[5]);
+ }
+
+ @Test
+ void testLargeWeights() {
+ // Graph with large weights
+ int[][] largeWeightGraph = {{0, 1000, 0}, {1000, 0, 2000}, {0, 2000, 0}};
+
+ DijkstraAlgorithm dijkstraLarge = new DijkstraAlgorithm(3);
+ int[] distances = dijkstraLarge.run(largeWeightGraph, 0);
+
+ assertArrayEquals(new int[] {0, 1000, 3000}, distances);
+ }
}
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/MatrixGraphsTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/MatrixGraphsTest.java
index cc8a2df872ce..eaff0222bd36 100644
--- a/src/test/java/com/thealgorithms/datastructures/graphs/MatrixGraphsTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/MatrixGraphsTest.java
@@ -137,4 +137,215 @@ void testDisconnectedGraph() {
assertTrue(dfs.containsAll(Arrays.asList(0, 1)));
assertTrue(bfs.containsAll(Arrays.asList(0, 1)));
}
+
+ @Test
+ void testSingleVertexGraphDfs() {
+ AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(1);
+
+ List dfs = graph.depthFirstOrder(0);
+ assertEquals(1, dfs.size());
+ assertEquals(0, dfs.getFirst());
+ }
+
+ @Test
+ void testSingleVertexGraphBfs() {
+ AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(1);
+
+ List bfs = graph.breadthFirstOrder(0);
+ assertEquals(1, bfs.size());
+ assertEquals(0, bfs.getFirst());
+ }
+
+ @Test
+ void testBfsLevelOrder() {
+ // Create a graph where BFS should visit level by level
+ // 0
+ // /|\
+ // 1 2 3
+ // |
+ // 4
+ AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5);
+ graph.addEdge(0, 1);
+ graph.addEdge(0, 2);
+ graph.addEdge(0, 3);
+ graph.addEdge(1, 4);
+
+ List bfs = graph.breadthFirstOrder(0);
+ assertEquals(5, bfs.size());
+ assertEquals(0, bfs.get(0));
+ // Level 1 vertices (1, 2, 3) should appear before level 2 vertex (4)
+ int indexOf4 = bfs.indexOf(4);
+ assertTrue(bfs.indexOf(1) < indexOf4);
+ assertTrue(bfs.indexOf(2) < indexOf4);
+ assertTrue(bfs.indexOf(3) < indexOf4);
+ }
+
+ @Test
+ void testDfsStartFromDifferentVertices() {
+ AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(4);
+ graph.addEdge(0, 1);
+ graph.addEdge(1, 2);
+ graph.addEdge(2, 3);
+
+ // DFS from vertex 0
+ List dfs0 = graph.depthFirstOrder(0);
+ assertEquals(4, dfs0.size());
+ assertEquals(0, dfs0.get(0));
+
+ // DFS from vertex 2
+ List dfs2 = graph.depthFirstOrder(2);
+ assertEquals(4, dfs2.size());
+ assertEquals(2, dfs2.get(0));
+
+ // DFS from vertex 3
+ List dfs3 = graph.depthFirstOrder(3);
+ assertEquals(4, dfs3.size());
+ assertEquals(3, dfs3.get(0));
+ }
+
+ @Test
+ void testBfsStartFromDifferentVertices() {
+ AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(4);
+ graph.addEdge(0, 1);
+ graph.addEdge(1, 2);
+ graph.addEdge(2, 3);
+
+ // BFS from vertex 0
+ List bfs0 = graph.breadthFirstOrder(0);
+ assertEquals(4, bfs0.size());
+ assertEquals(0, bfs0.get(0));
+
+ // BFS from vertex 2
+ List bfs2 = graph.breadthFirstOrder(2);
+ assertEquals(4, bfs2.size());
+ assertEquals(2, bfs2.get(0));
+ }
+
+ @Test
+ void testStarTopologyBfs() {
+ // Star graph: 0 is center connected to 1, 2, 3, 4
+ AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5);
+ graph.addEdge(0, 1);
+ graph.addEdge(0, 2);
+ graph.addEdge(0, 3);
+ graph.addEdge(0, 4);
+
+ List bfs = graph.breadthFirstOrder(0);
+ assertEquals(5, bfs.size());
+ assertEquals(0, bfs.get(0));
+ // All neighbors should be at distance 1
+ assertTrue(bfs.containsAll(Arrays.asList(1, 2, 3, 4)));
+ }
+
+ @Test
+ void testStarTopologyDfs() {
+ // Star graph: 0 is center connected to 1, 2, 3, 4
+ AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5);
+ graph.addEdge(0, 1);
+ graph.addEdge(0, 2);
+ graph.addEdge(0, 3);
+ graph.addEdge(0, 4);
+
+ List dfs = graph.depthFirstOrder(0);
+ assertEquals(5, dfs.size());
+ assertEquals(0, dfs.get(0));
+ assertTrue(dfs.containsAll(Arrays.asList(1, 2, 3, 4)));
+ }
+
+ @Test
+ void testNegativeStartVertexDfs() {
+ AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5);
+ graph.addEdge(0, 1);
+
+ List dfs = graph.depthFirstOrder(-1);
+ assertTrue(dfs.isEmpty());
+ }
+
+ @Test
+ void testNegativeStartVertexBfs() {
+ AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5);
+ graph.addEdge(0, 1);
+
+ List bfs = graph.breadthFirstOrder(-1);
+ assertTrue(bfs.isEmpty());
+ }
+
+ @Test
+ void testCompleteGraphKFour() {
+ // Complete graph K4: every vertex connected to every other vertex
+ AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(4);
+ graph.addEdge(0, 1);
+ graph.addEdge(0, 2);
+ graph.addEdge(0, 3);
+ graph.addEdge(1, 2);
+ graph.addEdge(1, 3);
+ graph.addEdge(2, 3);
+
+ assertEquals(6, graph.numberOfEdges());
+
+ List dfs = graph.depthFirstOrder(0);
+ List bfs = graph.breadthFirstOrder(0);
+
+ assertEquals(4, dfs.size());
+ assertEquals(4, bfs.size());
+ assertTrue(dfs.containsAll(Arrays.asList(0, 1, 2, 3)));
+ assertTrue(bfs.containsAll(Arrays.asList(0, 1, 2, 3)));
+ }
+
+ @Test
+ void testLargerGraphTraversal() {
+ // Create a larger graph with 10 vertices
+ AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(10);
+ graph.addEdge(0, 1);
+ graph.addEdge(0, 2);
+ graph.addEdge(1, 3);
+ graph.addEdge(1, 4);
+ graph.addEdge(2, 5);
+ graph.addEdge(2, 6);
+ graph.addEdge(3, 7);
+ graph.addEdge(4, 8);
+ graph.addEdge(5, 9);
+
+ List dfs = graph.depthFirstOrder(0);
+ List bfs = graph.breadthFirstOrder(0);
+
+ assertEquals(10, dfs.size());
+ assertEquals(10, bfs.size());
+ assertEquals(0, dfs.get(0));
+ assertEquals(0, bfs.get(0));
+ }
+
+ @Test
+ void testSelfLoop() {
+ AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(3);
+ graph.addEdge(0, 0); // Self loop
+ graph.addEdge(0, 1);
+ graph.addEdge(1, 2);
+
+ List dfs = graph.depthFirstOrder(0);
+ List bfs = graph.breadthFirstOrder(0);
+
+ assertEquals(3, dfs.size());
+ assertEquals(3, bfs.size());
+ }
+
+ @Test
+ void testLinearGraphTraversal() {
+ // Linear graph: 0 - 1 - 2 - 3 - 4
+ AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5);
+ graph.addEdge(0, 1);
+ graph.addEdge(1, 2);
+ graph.addEdge(2, 3);
+ graph.addEdge(3, 4);
+
+ List dfs = graph.depthFirstOrder(0);
+ List bfs = graph.breadthFirstOrder(0);
+
+ assertEquals(5, dfs.size());
+ assertEquals(5, bfs.size());
+
+ // In a linear graph, BFS and DFS starting from 0 should be the same
+ assertEquals(Arrays.asList(0, 1, 2, 3, 4), dfs);
+ assertEquals(Arrays.asList(0, 1, 2, 3, 4), bfs);
+ }
}
From a8bc9cc5258f68ced843b827cbabb1b60e80f35d Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 10 Dec 2025 10:33:35 +0000
Subject: [PATCH 194/272] chore(deps-dev): bump org.mockito:mockito-core from
5.20.0 to 5.21.0 (#7154)
Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.20.0 to 5.21.0.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v5.20.0...v5.21.0)
---
updated-dependencies:
- dependency-name: org.mockito:mockito-core
dependency-version: 5.21.0
dependency-type: direct:development
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Deniz Altunkapan
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 4baf7a5f99b0..185249a0ea0f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -42,7 +42,7 @@
org.mockito
mockito-core
- 5.20.0
+ 5.21.0
test
From 746457ce152909a76613cdd7ba69b0e7acd72e5b Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 13 Dec 2025 00:29:17 +0100
Subject: [PATCH 195/272] chore(deps): bump actions/cache from 4 to 5 in
/.github/workflows (#7162)
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)
---
updated-dependencies:
- dependency-name: actions/cache
dependency-version: '5'
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.github/workflows/infer.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/infer.yml b/.github/workflows/infer.yml
index c85b1d225f72..9d4dcf63000b 100644
--- a/.github/workflows/infer.yml
+++ b/.github/workflows/infer.yml
@@ -33,7 +33,7 @@ jobs:
- name: Cache infer build
id: cache-infer
- uses: actions/cache@v4
+ uses: actions/cache@v5
with:
path: infer
key: ${{ runner.os }}-infer-${{ env.year_week }}
From bccaf970baf8f7caa7ae08c0088e224625d8d5f0 Mon Sep 17 00:00:00 2001
From: utkarsh patel <153971829+Utkarsh-patel26@users.noreply.github.com>
Date: Sun, 14 Dec 2025 15:38:18 +0530
Subject: [PATCH 196/272] Add Z-Algorithm for Linear-Time String Pattern
Matching (#7124)
* Add Z-Algorithm (string pattern matching) with tests
* Add Z-Algorithm (string pattern matching) with tests
* Add Z-Algorithm (string pattern matching) with tests
* Fix checkstyle errors for ZAlgorithm
* Fix: clang-format and checkstyle compliance for ZAlgorithm
---
DIRECTORY.md | 2 +
.../com/thealgorithms/strings/ZAlgorithm.java | 48 +++++++++++++++++++
.../thealgorithms/strings/ZAlgorithmTest.java | 25 ++++++++++
3 files changed, 75 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/strings/ZAlgorithm.java
create mode 100644 src/test/java/com/thealgorithms/strings/ZAlgorithmTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index b8db96ffa993..6ea83fc6a60a 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -822,6 +822,7 @@
- 📄 [Upper](src/main/java/com/thealgorithms/strings/Upper.java)
- 📄 [ValidParentheses](src/main/java/com/thealgorithms/strings/ValidParentheses.java)
- 📄 [WordLadder](src/main/java/com/thealgorithms/strings/WordLadder.java)
+ - 📄 [ZAlgorithm](src/main/java/com/thealgorithms/strings/ZAlgorithm.java)
- 📁 **zigZagPattern**
- 📄 [ZigZagPattern](src/main/java/com/thealgorithms/strings/zigZagPattern/ZigZagPattern.java)
- 📁 **tree**
@@ -1579,6 +1580,7 @@
- 📄 [UpperTest](src/test/java/com/thealgorithms/strings/UpperTest.java)
- 📄 [ValidParenthesesTest](src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java)
- 📄 [WordLadderTest](src/test/java/com/thealgorithms/strings/WordLadderTest.java)
+ - 📄 [ZAlgorithmTest](src/test/java/com/thealgorithms/strings/ZAlgorithmTest.java)
- 📁 **zigZagPattern**
- 📄 [ZigZagPatternTest](src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java)
- 📁 **tree**
diff --git a/src/main/java/com/thealgorithms/strings/ZAlgorithm.java b/src/main/java/com/thealgorithms/strings/ZAlgorithm.java
new file mode 100644
index 000000000000..dc029b751f45
--- /dev/null
+++ b/src/main/java/com/thealgorithms/strings/ZAlgorithm.java
@@ -0,0 +1,48 @@
+/*
+ * https://en.wikipedia.org/wiki/Z-algorithm
+ */
+package com.thealgorithms.strings;
+
+public final class ZAlgorithm {
+
+ private ZAlgorithm() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ public static int[] zFunction(String s) {
+ int n = s.length();
+ int[] z = new int[n];
+ int l = 0;
+ int r = 0;
+
+ for (int i = 1; i < n; i++) {
+ if (i <= r) {
+ z[i] = Math.min(r - i + 1, z[i - l]);
+ }
+
+ while (i + z[i] < n && s.charAt(z[i]) == s.charAt(i + z[i])) {
+ z[i]++;
+ }
+
+ if (i + z[i] - 1 > r) {
+ l = i;
+ r = i + z[i] - 1;
+ }
+ }
+
+ return z;
+ }
+
+ public static int search(String text, String pattern) {
+ String s = pattern + "$" + text;
+ int[] z = zFunction(s);
+ int p = pattern.length();
+
+ for (int i = 0; i < z.length; i++) {
+ if (z[i] == p) {
+ return i - p - 1;
+ }
+ }
+ return -1;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/strings/ZAlgorithmTest.java b/src/test/java/com/thealgorithms/strings/ZAlgorithmTest.java
new file mode 100644
index 000000000000..df749ed9a8b5
--- /dev/null
+++ b/src/test/java/com/thealgorithms/strings/ZAlgorithmTest.java
@@ -0,0 +1,25 @@
+package com.thealgorithms.strings;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class ZAlgorithmTest {
+
+ @Test
+ void testZFunction() {
+ int[] z = ZAlgorithm.zFunction("aaaaa");
+ assertArrayEquals(new int[] {0, 4, 3, 2, 1}, z);
+ }
+
+ @Test
+ void testSearchFound() {
+ assertEquals(2, ZAlgorithm.search("abcabca", "cab"));
+ }
+
+ @Test
+ void testSearchNotFound() {
+ assertEquals(-1, ZAlgorithm.search("abcdef", "gh"));
+ }
+}
From aa914512030269fd30173cd3892804bac203aded Mon Sep 17 00:00:00 2001
From: Muhammad Junaid Khalid
Date: Sun, 14 Dec 2025 15:14:00 +0500
Subject: [PATCH 197/272] feat: Binary Tree to String algorithm added (Leetcode
606) (#6727)
* feat: BinaryTreeToString.java Added with tests
* fix: javadoc added to BinaryTreeToString
* fix: link to leetcode added
---
.../trees/BinaryTreeToString.java | 100 ++++++++++++++++++
.../trees/BinaryTreeToStringTest.java | 57 ++++++++++
2 files changed, 157 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/datastructures/trees/BinaryTreeToString.java
create mode 100644 src/test/java/com/thealgorithms/datastructures/trees/BinaryTreeToStringTest.java
diff --git a/src/main/java/com/thealgorithms/datastructures/trees/BinaryTreeToString.java b/src/main/java/com/thealgorithms/datastructures/trees/BinaryTreeToString.java
new file mode 100644
index 000000000000..2f9b3b489d56
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/trees/BinaryTreeToString.java
@@ -0,0 +1,100 @@
+package com.thealgorithms.datastructures.trees;
+
+/**
+ * Leetcode 606: Construct String from Binary Tree:
+ * https://leetcode.com/problems/construct-string-from-binary-tree/
+ *
+ * Utility class to convert a {@link BinaryTree} into its string representation.
+ *
+ * The conversion follows a preorder traversal pattern (root → left → right)
+ * and uses parentheses to denote the tree structure.
+ * Empty parentheses "()" are used to explicitly represent missing left children
+ * when a right child exists, ensuring the structure is unambiguous.
+ *
+ *
+ * Rules:
+ *
+ * - Each node is represented as {@code (value)}.
+ * - If a node has only a right child, include {@code ()} before the right
+ * child
+ * to indicate the missing left child.
+ * - If a node has no children, it appears as just {@code (value)}.
+ * - The outermost parentheses are removed from the final string.
+ *
+ *
+ * Example:
+ *
+ *
+ * Input tree:
+ * 1
+ * / \
+ * 2 3
+ * \
+ * 4
+ *
+ * Output string:
+ * "1(2()(4))(3)"
+ *
+ *
+ *
+ * This implementation matches the logic from LeetCode problem 606:
+ * Construct String from Binary Tree.
+ *
+ *
+ * @author Muhammad Junaid
+ * @see BinaryTree
+ */
+public class BinaryTreeToString {
+
+ /** String builder used to accumulate the string representation. */
+ private StringBuilder sb;
+
+ /**
+ * Converts a binary tree (given its root node) to its string representation.
+ *
+ * @param root the root node of the binary tree
+ * @return the string representation of the binary tree, or an empty string if
+ * the tree is null
+ */
+ public String tree2str(BinaryTree.Node root) {
+ if (root == null) {
+ return "";
+ }
+
+ sb = new StringBuilder();
+ dfs(root);
+
+ // Remove the leading and trailing parentheses added by the root call
+ return sb.substring(1, sb.length() - 1);
+ }
+
+ /**
+ * Performs a recursive depth-first traversal to build the string.
+ * Each recursive call appends the node value and its children (if any)
+ * enclosed in parentheses.
+ *
+ * @param node the current node being processed
+ */
+ private void dfs(BinaryTree.Node node) {
+ if (node == null) {
+ return;
+ }
+
+ sb.append("(").append(node.data);
+
+ // Recursively build left and right subtrees
+ if (node.left != null) {
+ dfs(node.left);
+ }
+
+ // Handle the special case: right child exists but left child is null
+ if (node.right != null && node.left == null) {
+ sb.append("()");
+ dfs(node.right);
+ } else if (node.right != null) {
+ dfs(node.right);
+ }
+
+ sb.append(")");
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/trees/BinaryTreeToStringTest.java b/src/test/java/com/thealgorithms/datastructures/trees/BinaryTreeToStringTest.java
new file mode 100644
index 000000000000..2461fd74143d
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/trees/BinaryTreeToStringTest.java
@@ -0,0 +1,57 @@
+package com.thealgorithms.datastructures.trees;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for the BinaryTreeToString class.
+ */
+public class BinaryTreeToStringTest {
+
+ @Test
+ public void testTreeToStringBasic() {
+ BinaryTree tree = new BinaryTree();
+ tree.put(1);
+ tree.put(2);
+ tree.put(3);
+ tree.put(4);
+
+ BinaryTreeToString converter = new BinaryTreeToString();
+ String result = converter.tree2str(tree.getRoot());
+
+ // Output will depend on insertion logic of BinaryTree.put()
+ // which is BST-style, so result = "1()(2()(3()(4)))"
+ Assertions.assertEquals("1()(2()(3()(4)))", result);
+ }
+
+ @Test
+ public void testSingleNodeTree() {
+ BinaryTree tree = new BinaryTree();
+ tree.put(10);
+
+ BinaryTreeToString converter = new BinaryTreeToString();
+ String result = converter.tree2str(tree.getRoot());
+
+ Assertions.assertEquals("10", result);
+ }
+
+ @Test
+ public void testComplexTreeStructure() {
+ BinaryTree.Node root = new BinaryTree.Node(10);
+ root.left = new BinaryTree.Node(5);
+ root.right = new BinaryTree.Node(20);
+ root.right.left = new BinaryTree.Node(15);
+ root.right.right = new BinaryTree.Node(25);
+
+ BinaryTreeToString converter = new BinaryTreeToString();
+ String result = converter.tree2str(root);
+
+ Assertions.assertEquals("10(5)(20(15)(25))", result);
+ }
+
+ @Test
+ public void testNullTree() {
+ BinaryTreeToString converter = new BinaryTreeToString();
+ Assertions.assertEquals("", converter.tree2str(null));
+ }
+}
From d9f2ac8340946f4c677a3ea1a5b9128a533086e0 Mon Sep 17 00:00:00 2001
From: Taranjeet Singh Kalsi
Date: Sun, 14 Dec 2025 15:59:14 +0530
Subject: [PATCH 198/272] Added program to check Lucky number (#6962)
added program for lucky number
---
.../com/thealgorithms/maths/LuckyNumber.java | 78 +++++++++++++++++++
.../thealgorithms/maths/LuckyNumberTest.java | 32 ++++++++
2 files changed, 110 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/maths/LuckyNumber.java
create mode 100644 src/test/java/com/thealgorithms/maths/LuckyNumberTest.java
diff --git a/src/main/java/com/thealgorithms/maths/LuckyNumber.java b/src/main/java/com/thealgorithms/maths/LuckyNumber.java
new file mode 100644
index 000000000000..70308e1e0edd
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/LuckyNumber.java
@@ -0,0 +1,78 @@
+package com.thealgorithms.maths;
+
+/**
+ * In number theory, a lucky number is a natural number in a set which is generated by a certain "sieve".
+ * This sieve is similar to the sieve of Eratosthenes that generates the primes,
+ * but it eliminates numbers based on their position in the remaining set,
+ * instead of their value (or position in the initial set of natural numbers).
+ *
+ * Wiki: https://en.wikipedia.org/wiki/Lucky_number
+ */
+public final class LuckyNumber {
+
+ private LuckyNumber() {
+ }
+
+ // Common validation method
+ private static void validatePositiveNumber(int number) {
+ if (number <= 0) {
+ throw new IllegalArgumentException("Number must be positive.");
+ }
+ }
+
+ // Function to check recursively for Lucky Number
+ private static boolean isLuckyRecursiveApproach(int n, int counter) {
+ // Base case: If counter exceeds n, number is lucky
+ if (counter > n) {
+ return true;
+ }
+
+ // If number is eliminated in this step, it's not lucky
+ if (n % counter == 0) {
+ return false;
+ }
+
+ // Calculate new position after removing every counter-th number
+ int newNumber = n - (n / counter);
+
+ // Recursive call for next round
+ return isLuckyRecursiveApproach(newNumber, counter + 1);
+ }
+
+ /**
+ * Check if {@code number} is a Lucky number or not using recursive approach
+ *
+ * @param number the number
+ * @return {@code true} if {@code number} is a Lucky number, otherwise false
+ */
+ public static boolean isLuckyNumber(int number) {
+ validatePositiveNumber(number);
+ int counterStarting = 2;
+ return isLuckyRecursiveApproach(number, counterStarting);
+ }
+
+ /**
+ * Check if {@code number} is a Lucky number or not using iterative approach
+ *
+ * @param number the number
+ * @return {@code true} if {@code number} is a Lucky number, otherwise false
+ */
+ public static boolean isLucky(int number) {
+ validatePositiveNumber(number);
+
+ int counter = 2; // Position starts from 2 (since first elimination happens at 2)
+ int position = number; // The position of the number in the sequence
+
+ while (counter <= position) {
+ if (position % counter == 0) {
+ return false;
+ } // Number is eliminated
+
+ // Update the position of n after removing every counter-th number
+ position = position - (position / counter);
+ counter++;
+ }
+
+ return true; // Survives all eliminations → Lucky Number
+ }
+}
diff --git a/src/test/java/com/thealgorithms/maths/LuckyNumberTest.java b/src/test/java/com/thealgorithms/maths/LuckyNumberTest.java
new file mode 100644
index 000000000000..91904316b25c
--- /dev/null
+++ b/src/test/java/com/thealgorithms/maths/LuckyNumberTest.java
@@ -0,0 +1,32 @@
+package com.thealgorithms.maths;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+class LuckyNumberTest {
+
+ @ParameterizedTest
+ @CsvSource({"1", "3", "13", "49", "109", "459", "949"})
+ void luckyNumbersTest(int n) {
+ assertTrue(LuckyNumber.isLucky(n));
+ assertTrue(LuckyNumber.isLuckyNumber(n));
+ }
+
+ @ParameterizedTest
+ @CsvSource({"2", "17", "100", "300", "700"})
+ void nonLuckyNumbersTest(int n) {
+ assertFalse(LuckyNumber.isLucky(n));
+ assertFalse(LuckyNumber.isLuckyNumber(n));
+ }
+
+ @ParameterizedTest
+ @CsvSource({"0", "-1"})
+ void throwsNegativeNumbersNotAllowed(int n) {
+ assertThrows(IllegalArgumentException.class, () -> LuckyNumber.isLucky(n));
+ assertThrows(IllegalArgumentException.class, () -> LuckyNumber.isLuckyNumber(n));
+ }
+}
From b76962d5ad9b66e13c757b65bf0a8d9843c52505 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 16 Dec 2025 17:53:29 +0100
Subject: [PATCH 199/272] chore(deps): bump com.puppycrawl.tools:checkstyle
from 12.2.0 to 12.3.0 (#7167)
Bumps [com.puppycrawl.tools:checkstyle](https://github.com/checkstyle/checkstyle) from 12.2.0 to 12.3.0.
- [Release notes](https://github.com/checkstyle/checkstyle/releases)
- [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-12.2.0...checkstyle-12.3.0)
---
updated-dependencies:
- dependency-name: com.puppycrawl.tools:checkstyle
dependency-version: 12.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>
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 185249a0ea0f..d60f8b9668e6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -112,7 +112,7 @@
com.puppycrawl.tools
checkstyle
- 12.2.0
+ 12.3.0
From 4f293b33e553af095305de23d72cf29c416a0c9f Mon Sep 17 00:00:00 2001
From: NYAMATHABAD KOUSHIK SAI <120590127+koushik-sai@users.noreply.github.com>
Date: Wed, 17 Dec 2025 21:18:00 +0530
Subject: [PATCH 200/272] [FEAT] Add Thin Lens formula for ray optics (#7170)
* [FEAT] Add Thin Lens formula for ray optics
* [CI] Re-run clang-format checks
* [CI] Re-run checks after rebase
* [STYLE] Apply clang-format to ThinLensTest
---------
Co-authored-by: Koushik Sai
---
.../com/thealgorithms/physics/ThinLens.java | 74 +++++++++++++++++++
.../thealgorithms/physics/ThinLensTest.java | 19 +++++
2 files changed, 93 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/physics/ThinLens.java
create mode 100644 src/test/java/com/thealgorithms/physics/ThinLensTest.java
diff --git a/src/main/java/com/thealgorithms/physics/ThinLens.java b/src/main/java/com/thealgorithms/physics/ThinLens.java
new file mode 100644
index 000000000000..5fb29d8c41e4
--- /dev/null
+++ b/src/main/java/com/thealgorithms/physics/ThinLens.java
@@ -0,0 +1,74 @@
+package com.thealgorithms.physics;
+
+/**
+ * Implements the Thin Lens Formula used in ray optics:
+ *
+ *
+ * 1/f = 1/v + 1/u
+ *
+ *
+ * where:
+ *
+ * - f = focal length
+ * - u = object distance
+ * - v = image distance
+ *
+ *
+ * Uses the Cartesian sign convention.
+ *
+ * @see Thin Lens
+ */
+public final class ThinLens {
+
+ private ThinLens() {
+ throw new AssertionError("No instances.");
+ }
+
+ /**
+ * Computes the image distance using the thin lens formula.
+ *
+ * @param focalLength focal length of the lens (f)
+ * @param objectDistance object distance (u)
+ * @return image distance (v)
+ * @throws IllegalArgumentException if focal length or object distance is zero
+ */
+ public static double imageDistance(double focalLength, double objectDistance) {
+
+ if (focalLength == 0 || objectDistance == 0) {
+ throw new IllegalArgumentException("Focal length and object distance must be non-zero.");
+ }
+
+ return 1.0 / ((1.0 / focalLength) - (1.0 / objectDistance));
+ }
+
+ /**
+ * Computes magnification of the image.
+ *
+ *
+ * m = v / u
+ *
+ *
+ * @param imageDistance image distance (v)
+ * @param objectDistance object distance (u)
+ * @return magnification
+ * @throws IllegalArgumentException if object distance is zero
+ */
+ public static double magnification(double imageDistance, double objectDistance) {
+
+ if (objectDistance == 0) {
+ throw new IllegalArgumentException("Object distance must be non-zero.");
+ }
+
+ return imageDistance / objectDistance;
+ }
+
+ /**
+ * Determines whether the image formed is real or virtual.
+ *
+ * @param imageDistance image distance (v)
+ * @return {@code true} if image is real, {@code false} if virtual
+ */
+ public static boolean isRealImage(double imageDistance) {
+ return imageDistance > 0;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/physics/ThinLensTest.java b/src/test/java/com/thealgorithms/physics/ThinLensTest.java
new file mode 100644
index 000000000000..cf7e94676819
--- /dev/null
+++ b/src/test/java/com/thealgorithms/physics/ThinLensTest.java
@@ -0,0 +1,19 @@
+package com.thealgorithms.physics;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+class ThinLensTest {
+
+ @Test
+ void testConvexLensRealImage() {
+ double v = ThinLens.imageDistance(10, 20);
+ assertEquals(20, v, 1e-6);
+ }
+
+ @Test
+ void testMagnification() {
+ assertEquals(2.0, ThinLens.magnification(20, 10), 1e-6);
+ }
+}
From 2911a7b52c1032591d2aa23feef5669fa43c7961 Mon Sep 17 00:00:00 2001
From: Rajuri Likhitha
Date: Thu, 18 Dec 2025 02:44:12 +0530
Subject: [PATCH 201/272] ExtendedEuclideanAlgorithm (#7172)
* commit1
* Fix clang-format spacing in array declarations
---
.../maths/ExtendedEuclideanAlgorithm.java | 48 +++++++++++++++++++
.../maths/ExtendedEuclideanAlgorithmTest.java | 47 ++++++++++++++++++
2 files changed, 95 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/maths/ExtendedEuclideanAlgorithm.java
create mode 100644 src/test/java/com/thealgorithms/maths/ExtendedEuclideanAlgorithmTest.java
diff --git a/src/main/java/com/thealgorithms/maths/ExtendedEuclideanAlgorithm.java b/src/main/java/com/thealgorithms/maths/ExtendedEuclideanAlgorithm.java
new file mode 100644
index 000000000000..4934d4493bf2
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/ExtendedEuclideanAlgorithm.java
@@ -0,0 +1,48 @@
+package com.thealgorithms.maths;
+
+/**
+ * In mathematics, the extended Euclidean algorithm is an extension to the
+ * Euclidean algorithm, and computes, in addition to the greatest common divisor
+ * (gcd) of integers a and b, also the coefficients of Bézout's identity, which
+ * are integers x and y such that ax + by = gcd(a, b).
+ *
+ *
+ * For more details, see
+ * https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
+ */
+public final class ExtendedEuclideanAlgorithm {
+
+ private ExtendedEuclideanAlgorithm() {
+ }
+
+ /**
+ * This method implements the extended Euclidean algorithm.
+ *
+ * @param a The first number.
+ * @param b The second number.
+ * @return An array of three integers:
+ *
+ * - Index 0: The greatest common divisor (gcd) of a and b.
+ * - Index 1: The value of x in the equation ax + by = gcd(a, b).
+ * - Index 2: The value of y in the equation ax + by = gcd(a, b).
+ *
+ */
+ public static long[] extendedGCD(long a, long b) {
+ if (b == 0) {
+ // Base case: gcd(a, 0) = a. The equation is a*1 + 0*0 = a.
+ return new long[] {a, 1, 0};
+ }
+
+ // Recursive call
+ long[] result = extendedGCD(b, a % b);
+ long gcd = result[0];
+ long x1 = result[1];
+ long y1 = result[2];
+
+ // Update coefficients using the results from the recursive call
+ long x = y1;
+ long y = x1 - a / b * y1;
+
+ return new long[] {gcd, x, y};
+ }
+}
diff --git a/src/test/java/com/thealgorithms/maths/ExtendedEuclideanAlgorithmTest.java b/src/test/java/com/thealgorithms/maths/ExtendedEuclideanAlgorithmTest.java
new file mode 100644
index 000000000000..56c005fd51ae
--- /dev/null
+++ b/src/test/java/com/thealgorithms/maths/ExtendedEuclideanAlgorithmTest.java
@@ -0,0 +1,47 @@
+package com.thealgorithms.maths;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class ExtendedEuclideanAlgorithmTest {
+
+ /**
+ * Verifies that the returned values satisfy Bézout's identity: a*x + b*y =
+ * gcd(a, b)
+ */
+ private void verifyBezoutIdentity(long a, long b, long[] result) {
+ long gcd = result[0];
+ long x = result[1];
+ long y = result[2];
+ assertEquals(a * x + b * y, gcd, "Bézout's identity failed for gcd(" + a + ", " + b + ")");
+ }
+
+ @Test
+ public void testExtendedGCD() {
+ // Test case 1: General case gcd(30, 50) = 10
+ long[] result1 = ExtendedEuclideanAlgorithm.extendedGCD(30, 50);
+ assertEquals(10, result1[0], "Test Case 1 Failed: gcd(30, 50) should be 10");
+ verifyBezoutIdentity(30, 50, result1);
+
+ // Test case 2: Another general case gcd(240, 46) = 2
+ long[] result2 = ExtendedEuclideanAlgorithm.extendedGCD(240, 46);
+ assertEquals(2, result2[0], "Test Case 2 Failed: gcd(240, 46) should be 2");
+ verifyBezoutIdentity(240, 46, result2);
+
+ // Test case 3: Base case where b is 0, gcd(10, 0) = 10
+ long[] result3 = ExtendedEuclideanAlgorithm.extendedGCD(10, 0);
+ assertEquals(10, result3[0], "Test Case 3 Failed: gcd(10, 0) should be 10");
+ verifyBezoutIdentity(10, 0, result3);
+
+ // Test case 4: Numbers are co-prime gcd(17, 13) = 1
+ long[] result4 = ExtendedEuclideanAlgorithm.extendedGCD(17, 13);
+ assertEquals(1, result4[0], "Test Case 4 Failed: gcd(17, 13) should be 1");
+ verifyBezoutIdentity(17, 13, result4);
+
+ // Test case 5: One number is a multiple of the other gcd(100, 20) = 20
+ long[] result5 = ExtendedEuclideanAlgorithm.extendedGCD(100, 20);
+ assertEquals(20, result5[0], "Test Case 5 Failed: gcd(100, 20) should be 20");
+ verifyBezoutIdentity(100, 20, result5);
+ }
+}
From 7d51c7f32097b488bab330f858391387ce4ce72c Mon Sep 17 00:00:00 2001
From: Saniya Mane <185913688+Saniya2701@users.noreply.github.com>
Date: Thu, 18 Dec 2025 13:25:03 +0530
Subject: [PATCH 202/272] Add additional edge cases to GCD unit tests (#7174)
* Add additional edge cases to GCD unit tests
* Rename GCD test methods and add descriptive names
* Fix formatting in GCD tests
---------
Co-authored-by: Deniz Altunkapan
---
.../java/com/thealgorithms/maths/GCDTest.java | 58 +++++++++++++------
1 file changed, 39 insertions(+), 19 deletions(-)
diff --git a/src/test/java/com/thealgorithms/maths/GCDTest.java b/src/test/java/com/thealgorithms/maths/GCDTest.java
index bac3f8f7596c..6bc870e94df9 100644
--- a/src/test/java/com/thealgorithms/maths/GCDTest.java
+++ b/src/test/java/com/thealgorithms/maths/GCDTest.java
@@ -6,57 +6,77 @@
public class GCDTest {
@Test
- void test1() {
+ void testNegativeAndZeroThrowsException() {
Assertions.assertThrows(ArithmeticException.class, () -> GCD.gcd(-1, 0));
}
@Test
- void test2() {
+ void testPositiveAndNegativeThrowsException() {
Assertions.assertThrows(ArithmeticException.class, () -> GCD.gcd(10, -2));
}
@Test
- void test3() {
+ void testBothNegativeThrowsException() {
Assertions.assertThrows(ArithmeticException.class, () -> GCD.gcd(-5, -3));
}
@Test
- void test4() {
- Assertions.assertEquals(GCD.gcd(0, 2), 2);
+ void testZeroAndPositiveReturnsPositive() {
+ Assertions.assertEquals(2, GCD.gcd(0, 2));
}
@Test
- void test5() {
- Assertions.assertEquals(GCD.gcd(10, 0), 10);
+ void testPositiveAndZeroReturnsPositive() {
+ Assertions.assertEquals(10, GCD.gcd(10, 0));
}
@Test
- void test6() {
- Assertions.assertEquals(GCD.gcd(1, 0), 1);
+ void testOneAndZeroReturnsOne() {
+ Assertions.assertEquals(1, GCD.gcd(1, 0));
}
@Test
- void test7() {
- Assertions.assertEquals(GCD.gcd(9, 6), 3);
+ void testTwoPositiveNumbers() {
+ Assertions.assertEquals(3, GCD.gcd(9, 6));
}
@Test
- void test8() {
- Assertions.assertEquals(GCD.gcd(48, 18, 30, 12), 6);
+ void testMultipleArgumentsGcd() {
+ Assertions.assertEquals(6, GCD.gcd(48, 18, 30, 12));
}
@Test
- void testArrayGcd1() {
- Assertions.assertEquals(GCD.gcd(new int[] {9, 6}), 3);
+ void testArrayInputGcd() {
+ Assertions.assertEquals(3, GCD.gcd(new int[] {9, 6}));
}
@Test
- void testArrayGcd2() {
- Assertions.assertEquals(GCD.gcd(new int[] {2 * 3 * 5 * 7, 2 * 5 * 5 * 5, 2 * 5 * 11, 5 * 5 * 5 * 13}), 5);
+ void testArrayWithCommonFactor() {
+ Assertions.assertEquals(5, GCD.gcd(new int[] {2 * 3 * 5 * 7, 2 * 5 * 5 * 5, 2 * 5 * 11, 5 * 5 * 5 * 13}));
}
@Test
- void testArrayGcdForEmptyInput() {
- Assertions.assertEquals(GCD.gcd(new int[] {}), 0);
+ void testEmptyArrayReturnsZero() {
+ Assertions.assertEquals(0, GCD.gcd(new int[] {}));
+ }
+
+ @Test
+ void testSameNumbers() {
+ Assertions.assertEquals(7, GCD.gcd(7, 7));
+ }
+
+ @Test
+ void testPrimeNumbersHaveGcdOne() {
+ Assertions.assertEquals(1, GCD.gcd(13, 17));
+ }
+
+ @Test
+ void testSingleElementArrayReturnsElement() {
+ Assertions.assertEquals(42, GCD.gcd(new int[] {42}));
+ }
+
+ @Test
+ void testLargeNumbers() {
+ Assertions.assertEquals(12, GCD.gcd(123456, 789012));
}
}
From 48e02b3bacc80600297812733c3ed483d265531c Mon Sep 17 00:00:00 2001
From: Adityaraj Solanki
Date: Thu, 18 Dec 2025 21:39:55 +0530
Subject: [PATCH 203/272] Add input validation for negative values in
FibonacciSeries (#7177)
---
.../java/com/thealgorithms/recursion/FibonacciSeries.java | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/main/java/com/thealgorithms/recursion/FibonacciSeries.java b/src/main/java/com/thealgorithms/recursion/FibonacciSeries.java
index e5f474085367..9bc6da2f7443 100644
--- a/src/main/java/com/thealgorithms/recursion/FibonacciSeries.java
+++ b/src/main/java/com/thealgorithms/recursion/FibonacciSeries.java
@@ -12,10 +12,12 @@ private FibonacciSeries() {
throw new UnsupportedOperationException("Utility class");
}
public static int fibonacci(int n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("n must be a non-negative integer");
+ }
if (n <= 1) {
return n;
- } else {
- return fibonacci(n - 1) + fibonacci(n - 2);
}
+ return fibonacci(n - 1) + fibonacci(n - 2);
}
}
From bb334881e938c8728d0add1f08d6b9d9f4bd8970 Mon Sep 17 00:00:00 2001
From: Gopal Gupta <143406016+gopaljilab@users.noreply.github.com>
Date: Sat, 20 Dec 2025 19:12:34 +0530
Subject: [PATCH 204/272] Implement LengthOfLastWord algorithm and add JUnit
tests (#7057)
* Implement LengthOfLastWord algorithm in strings package
* Add JUnit tests for LengthOfLastWord algorithm
* style: fix import order and spacing for clang-format
---
.../strings/LengthOfLastWord.java | 51 +++++++++++++++++++
.../strings/LengthOfLastWordTest.java | 18 +++++++
2 files changed, 69 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/strings/LengthOfLastWord.java
create mode 100644 src/test/java/com/thealgorithms/strings/LengthOfLastWordTest.java
diff --git a/src/main/java/com/thealgorithms/strings/LengthOfLastWord.java b/src/main/java/com/thealgorithms/strings/LengthOfLastWord.java
new file mode 100644
index 000000000000..7eed59a5ef99
--- /dev/null
+++ b/src/main/java/com/thealgorithms/strings/LengthOfLastWord.java
@@ -0,0 +1,51 @@
+package com.thealgorithms.strings;
+
+/**
+ * The {@code LengthOfLastWord} class provides a utility method to determine
+ * the length of the last word in a given string.
+ *
+ * A "word" is defined as a maximal substring consisting of non-space
+ * characters only. Trailing spaces at the end of the string are ignored.
+ *
+ *
Example:
+ *
{@code
+ * LengthOfLastWord obj = new LengthOfLastWord();
+ * System.out.println(obj.lengthOfLastWord("Hello World")); // Output: 5
+ * System.out.println(obj.lengthOfLastWord(" fly me to the moon ")); // Output: 4
+ * System.out.println(obj.lengthOfLastWord("luffy is still joyboy")); // Output: 6
+ * }
+ *
+ * This implementation runs in O(n) time complexity, where n is the length
+ * of the input string, and uses O(1) additional space.
+ */
+public class LengthOfLastWord {
+
+ /**
+ * Returns the length of the last word in the specified string.
+ *
+ *
The method iterates from the end of the string, skipping trailing
+ * spaces first, and then counts the number of consecutive non-space characters
+ * characters until another space (or the beginning of the string) is reached.
+ *
+ * @param s the input string to analyze
+ * @return the length of the last word in {@code s}; returns 0 if there is no word
+ * @throws NullPointerException if {@code s} is {@code null}
+ */
+ public int lengthOfLastWord(String s) {
+ int sizeOfString = s.length() - 1;
+ int lastWordLength = 0;
+
+ // Skip trailing spaces from the end of the string
+ while (sizeOfString >= 0 && s.charAt(sizeOfString) == ' ') {
+ sizeOfString--;
+ }
+
+ // Count the characters of the last word
+ while (sizeOfString >= 0 && s.charAt(sizeOfString) != ' ') {
+ lastWordLength++;
+ sizeOfString--;
+ }
+
+ return lastWordLength;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/strings/LengthOfLastWordTest.java b/src/test/java/com/thealgorithms/strings/LengthOfLastWordTest.java
new file mode 100644
index 000000000000..46a0a6eb0008
--- /dev/null
+++ b/src/test/java/com/thealgorithms/strings/LengthOfLastWordTest.java
@@ -0,0 +1,18 @@
+package com.thealgorithms.strings;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class LengthOfLastWordTest {
+ @Test
+ public void testLengthOfLastWord() {
+ assertEquals(5, new LengthOfLastWord().lengthOfLastWord("Hello World"));
+ assertEquals(4, new LengthOfLastWord().lengthOfLastWord(" fly me to the moon "));
+ assertEquals(6, new LengthOfLastWord().lengthOfLastWord("luffy is still joyboy"));
+ assertEquals(5, new LengthOfLastWord().lengthOfLastWord("Hello"));
+ assertEquals(0, new LengthOfLastWord().lengthOfLastWord(" "));
+ assertEquals(0, new LengthOfLastWord().lengthOfLastWord(""));
+ assertEquals(3, new LengthOfLastWord().lengthOfLastWord("JUST LIE "));
+ }
+}
From 1eb0d61730e033bbc37bab67f795f9fa3a8fc2b1 Mon Sep 17 00:00:00 2001
From: HxCodes
Date: Sun, 21 Dec 2025 21:03:25 +0530
Subject: [PATCH 205/272] Improve documentation and inline comments for
QuickSort algorithm (#7182)
* Improve QuickSort documentation with detailed comments and explanations
* Format QuickSort documentation and fix JavaDoc layout
---
.../com/thealgorithms/sorts/QuickSort.java | 67 +++++++++++++------
1 file changed, 45 insertions(+), 22 deletions(-)
diff --git a/src/main/java/com/thealgorithms/sorts/QuickSort.java b/src/main/java/com/thealgorithms/sorts/QuickSort.java
index a025e6909259..b0ca8b9f159d 100644
--- a/src/main/java/com/thealgorithms/sorts/QuickSort.java
+++ b/src/main/java/com/thealgorithms/sorts/QuickSort.java
@@ -1,24 +1,36 @@
package com.thealgorithms.sorts;
/**
- * @author Varun Upadhyay (https://github.com/varunu28)
- * @author Podshivalov Nikita (https://github.com/nikitap492)
+ * QuickSort is a divide-and-conquer sorting algorithm.
+ *
+ * The algorithm selects a pivot element and partitions the array into two
+ * subarrays such that:
+ *
+ * - Elements smaller than the pivot are placed on the left
+ * - Elements greater than the pivot are placed on the right
+ *
+ *
+ * The subarrays are then recursively sorted until the entire array is ordered.
+ *
+ *
This implementation uses randomization to reduce the probability of
+ * encountering worst-case performance on already sorted inputs.
+ *
+ *
Time Complexity:
+ *
+ * - Best Case: O(n log n)
+ * - Average Case: O(n log n)
+ * - Worst Case: O(n^2)
+ *
+ *
+ * Space Complexity: O(log n) due to recursion stack (in-place sorting).
+ *
+ * @author Varun Upadhyay
+ * @author Podshivalov Nikita
* @see SortAlgorithm
*/
+
class QuickSort implements SortAlgorithm {
- /**
- * Generic Quick Sort algorithm.
- *
- * Time Complexity:
- * - Best case: O(n log n) – pivot splits array roughly in half each time.
- * - Average case: O(n log n)
- * - Worst case: O(n^2) – occurs when pivot consistently produces unbalanced splits.
- *
- * Space Complexity: O(log n) – recursion stack, in-place sorting.
- *
- * @see SortAlgorithm
- */
@Override
public > T[] sort(T[] array) {
doSort(array, 0, array.length - 1);
@@ -28,27 +40,33 @@ public > T[] sort(T[] array) {
/**
* The sorting process
*
- * @param left The first index of an array
- * @param right The last index of an array
* @param array The array to be sorted
+ * @param left The first index of an array
+ * @param right The last index of an array
*/
private static > void doSort(T[] array, final int left, final int right) {
+ // Continue sorting only if the subarray has more than one element
if (left < right) {
+ // Randomly choose a pivot and partition the array
final int pivot = randomPartition(array, left, right);
+ // Recursively sort elements before the pivot
doSort(array, left, pivot - 1);
+ // Recursively sort elements after the pivot
doSort(array, pivot, right);
}
}
/**
- * Randomize the array to avoid the basically ordered sequences
+ * Randomizes the array to avoid already ordered or nearly ordered sequences
*
* @param array The array to be sorted
- * @param left The first index of an array
+ * @param left The first index of an array
* @param right The last index of an array
* @return the partition index of the array
*/
private static > int randomPartition(T[] array, final int left, final int right) {
+ // Randomizing the pivot helps avoid worst-case performance
+ // for already sorted or nearly sorted arrays
final int randomIndex = left + (int) (Math.random() * (right - left + 1));
SortUtils.swap(array, randomIndex, right);
return partition(array, left, right);
@@ -58,21 +76,26 @@ private static > int randomPartition(T[] array, final in
* This method finds the partition index for an array
*
* @param array The array to be sorted
- * @param left The first index of an array
- * @param right The last index of an array Finds the partition index of an
- * array
+ * @param left The first index of an array
+ * @param right The last index of an array
*/
private static > int partition(T[] array, int left, int right) {
final int mid = (left + right) >>> 1;
+ // Choose the middle element as the pivot
final T pivot = array[mid];
-
+ // Move the left and right pointers towards each other
while (left <= right) {
+ // Move left pointer until an element >= pivot is found
while (SortUtils.less(array[left], pivot)) {
++left;
}
+
+ // Move right pointer until an element <= pivot is found
while (SortUtils.less(pivot, array[right])) {
--right;
}
+
+ // Swap elements that are on the wrong side of the pivot
if (left <= right) {
SortUtils.swap(array, left, right);
++left;
From 2707da25e35f6973ceacdf4aa7dde9ecf7d4d34c Mon Sep 17 00:00:00 2001
From: NYAMATHABAD KOUSHIK SAI <120590127+koushik-sai@users.noreply.github.com>
Date: Tue, 23 Dec 2025 01:45:50 +0530
Subject: [PATCH 206/272] Add recursive factorial implementation with tests
(#7178)
* Add recursive factorial implementation with tests
* [STYLE] Apply clang-format
* Move recursive factorial to recursion package and remove duplicate
* Move recursive factorial to recursion package and remove duplicate
* Apply clang-format to factorial recursion tests
* Apply clang-format to factorial recursion tests
---------
Co-authored-by: Koushik Sai
Co-authored-by: Deniz Altunkapan
---
.../thealgorithms/{maths => recursion}/FactorialRecursion.java | 2 +-
.../{maths => recursion}/FactorialRecursionTest.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
rename src/main/java/com/thealgorithms/{maths => recursion}/FactorialRecursion.java (92%)
rename src/test/java/com/thealgorithms/{maths => recursion}/FactorialRecursionTest.java (96%)
diff --git a/src/main/java/com/thealgorithms/maths/FactorialRecursion.java b/src/main/java/com/thealgorithms/recursion/FactorialRecursion.java
similarity index 92%
rename from src/main/java/com/thealgorithms/maths/FactorialRecursion.java
rename to src/main/java/com/thealgorithms/recursion/FactorialRecursion.java
index d9bafd1e39e9..673f216bdc9a 100644
--- a/src/main/java/com/thealgorithms/maths/FactorialRecursion.java
+++ b/src/main/java/com/thealgorithms/recursion/FactorialRecursion.java
@@ -1,4 +1,4 @@
-package com.thealgorithms.maths;
+package com.thealgorithms.recursion;
public final class FactorialRecursion {
private FactorialRecursion() {
diff --git a/src/test/java/com/thealgorithms/maths/FactorialRecursionTest.java b/src/test/java/com/thealgorithms/recursion/FactorialRecursionTest.java
similarity index 96%
rename from src/test/java/com/thealgorithms/maths/FactorialRecursionTest.java
rename to src/test/java/com/thealgorithms/recursion/FactorialRecursionTest.java
index db18b46356b4..198fcd558f63 100644
--- a/src/test/java/com/thealgorithms/maths/FactorialRecursionTest.java
+++ b/src/test/java/com/thealgorithms/recursion/FactorialRecursionTest.java
@@ -1,4 +1,4 @@
-package com.thealgorithms.maths;
+package com.thealgorithms.recursion;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
From 51335cc18adc988848bfec71fb291b39928e05dc Mon Sep 17 00:00:00 2001
From: NYAMATHABAD KOUSHIK SAI <120590127+koushik-sai@users.noreply.github.com>
Date: Sat, 27 Dec 2025 22:25:23 +0530
Subject: [PATCH 207/272] Add Immutable HashMap implementation (#7183)
* Add immutable HashMap implementation
* Add immutable HashMap implementation
* Applied clang-format
---------
Co-authored-by: Koushik Sai
---
.../hashmap/hashing/ImmutableHashMap.java | 115 ++++++++++++++++++
.../hashmap/hashing/ImmutableHashMapTest.java | 55 +++++++++
2 files changed, 170 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/datastructures/hashmap/hashing/ImmutableHashMap.java
create mode 100644 src/test/java/com/thealgorithms/datastructures/hashmap/hashing/ImmutableHashMapTest.java
diff --git a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/ImmutableHashMap.java b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/ImmutableHashMap.java
new file mode 100644
index 000000000000..f6e09ec623b6
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/ImmutableHashMap.java
@@ -0,0 +1,115 @@
+package com.thealgorithms.datastructures.hashmap.hashing;
+
+/**
+ * Immutable HashMap implementation using separate chaining.
+ *
+ * This HashMap does not allow modification of existing instances.
+ * Any update operation returns a new ImmutableHashMap.
+ *
+ * @param key type
+ * @param value type
+ */
+public final class ImmutableHashMap {
+
+ private static final int DEFAULT_CAPACITY = 16;
+
+ private final Node[] table;
+ private final int size;
+
+ /**
+ * Private constructor to enforce immutability.
+ */
+ private ImmutableHashMap(Node[] table, int size) {
+ this.table = table;
+ this.size = size;
+ }
+
+ /**
+ * Creates an empty ImmutableHashMap.
+ *
+ * @param key type
+ * @param value type
+ * @return empty ImmutableHashMap
+ */
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public static ImmutableHashMap empty() {
+ Node[] table = (Node[]) new Node[DEFAULT_CAPACITY];
+ return new ImmutableHashMap<>(table, 0);
+ }
+
+ /**
+ * Returns a new ImmutableHashMap with the given key-value pair added.
+ *
+ * @param key key to add
+ * @param value value to associate
+ * @return new ImmutableHashMap instance
+ */
+ public ImmutableHashMap put(K key, V value) {
+ Node[] newTable = table.clone();
+ int index = hash(key);
+
+ newTable[index] = new Node<>(key, value, newTable[index]);
+ return new ImmutableHashMap<>(newTable, size + 1);
+ }
+
+ /**
+ * Retrieves the value associated with the given key.
+ *
+ * @param key key to search
+ * @return value if found, otherwise null
+ */
+ public V get(K key) {
+ int index = hash(key);
+ Node current = table[index];
+
+ while (current != null) {
+ if ((key == null && current.key == null) || (key != null && key.equals(current.key))) {
+ return current.value;
+ }
+ current = current.next;
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the given key exists in the map.
+ *
+ * @param key key to check
+ * @return true if key exists, false otherwise
+ */
+ public boolean containsKey(K key) {
+ return get(key) != null;
+ }
+
+ /**
+ * Returns the number of key-value pairs.
+ *
+ * @return size of the map
+ */
+ public int size() {
+ return size;
+ }
+
+ /**
+ * Computes hash index for a given key.
+ */
+ private int hash(K key) {
+ return key == null ? 0 : (key.hashCode() & Integer.MAX_VALUE) % table.length;
+ }
+
+ /**
+ * Node class for separate chaining.
+ */
+ private static final class Node {
+
+ private final K key;
+ private final V value;
+ private final Node next;
+
+ private Node(K key, V value, Node next) {
+ this.key = key;
+ this.value = value;
+ this.next = next;
+ }
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/ImmutableHashMapTest.java b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/ImmutableHashMapTest.java
new file mode 100644
index 000000000000..3d3fe63d775a
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/ImmutableHashMapTest.java
@@ -0,0 +1,55 @@
+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.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+class ImmutableHashMapTest {
+
+ @Test
+ void testEmptyMap() {
+ ImmutableHashMap map = ImmutableHashMap.empty();
+
+ assertEquals(0, map.size());
+ assertNull(map.get("A"));
+ }
+
+ @Test
+ void testPutDoesNotModifyOriginalMap() {
+ ImmutableHashMap map1 = ImmutableHashMap.empty();
+
+ ImmutableHashMap map2 = map1.put("A", 1);
+
+ assertEquals(0, map1.size());
+ assertEquals(1, map2.size());
+ assertNull(map1.get("A"));
+ assertEquals(1, map2.get("A"));
+ }
+
+ @Test
+ void testMultiplePuts() {
+ ImmutableHashMap map = ImmutableHashMap.empty().put("A", 1).put("B", 2);
+
+ assertEquals(2, map.size());
+ assertEquals(1, map.get("A"));
+ assertEquals(2, map.get("B"));
+ }
+
+ @Test
+ void testContainsKey() {
+ ImmutableHashMap map = ImmutableHashMap.empty().put("X", 100);
+
+ assertTrue(map.containsKey("X"));
+ assertFalse(map.containsKey("Y"));
+ }
+
+ @Test
+ void testNullKey() {
+ ImmutableHashMap map = ImmutableHashMap.empty().put(null, 50);
+
+ assertEquals(50, map.get(null));
+ }
+}
From d382e656f20eaddc2d91c723519a2d8775e7dc57 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20S=C3=A1nchez=20N=C3=BA=C3=B1ez?=
Date: Sun, 28 Dec 2025 10:53:12 +0100
Subject: [PATCH 208/272] Adding method to check wether a matrix is stochastic
(#7184)
* Add StochasticMatrix utility class
This class provides methods to check if a matrix is row-stochastic or column-stochastic, ensuring all elements are non-negative and the sums of rows or columns equal 1.
* Change package from maths to matrix
Updated package declaration for StochasticMatrix class.
* Change package declaration in StochasticMatrixTest
* Delete src/test/java/com/thealgorithms/StochasticMatrixTest.java
* Refactor matrix initialization for test cases
* Fix formatting of matrix initialization in tests
* Remove unnecessary newline in StochasticMatrix
* Add import statement for JUnit in StochasticMatrixTest
* Add additional assertions to StochasticMatrixTest
* Clean up import statements in StochasticMatrixTest
Removed unused import statements for cleaner code.
* Reorder import statements in StochasticMatrixTest
* Remove unused import assertThrows from StochasticMatrixTest
Removed unused import for assertThrows.
---
.../matrix/StochasticMatrix.java | 74 +++++++++++++++++++
.../matrix/StochasticMatrixTest.java | 28 +++++++
2 files changed, 102 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/matrix/StochasticMatrix.java
create mode 100644 src/test/java/com/thealgorithms/matrix/StochasticMatrixTest.java
diff --git a/src/main/java/com/thealgorithms/matrix/StochasticMatrix.java b/src/main/java/com/thealgorithms/matrix/StochasticMatrix.java
new file mode 100644
index 000000000000..8b071113f9cc
--- /dev/null
+++ b/src/main/java/com/thealgorithms/matrix/StochasticMatrix.java
@@ -0,0 +1,74 @@
+package com.thealgorithms.matrix;
+
+/**
+ * Utility class to check whether a matrix is stochastic.
+ * A matrix is stochastic if all its elements are non-negative
+ * and the sum of each row or column is equal to 1.
+ *Reference: https://en.wikipedia.org/wiki/Stochastic_matrix
+ */
+public final class StochasticMatrix {
+
+ private static final double TOLERANCE = 1e-9;
+
+ private StochasticMatrix() {
+ // Utility class
+ }
+ /**
+ * Checks if a matrix is row-stochastic.
+ *
+ * @param matrix the matrix to check
+ * @return true if the matrix is row-stochastic
+ * @throws IllegalArgumentException if matrix is null or empty
+ */
+ public static boolean isRowStochastic(double[][] matrix) {
+ validateMatrix(matrix);
+
+ for (double[] row : matrix) {
+ double sum = 0.0;
+ for (double value : row) {
+ if (value < 0) {
+ return false;
+ }
+ sum += value;
+ }
+ if (Math.abs(sum - 1.0) > TOLERANCE) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Checks if a matrix is column-stochastic.
+ *
+ * @param matrix the matrix to check
+ * @return true if the matrix is column-stochastic
+ * @throws IllegalArgumentException if matrix is null or empty
+ */
+ public static boolean isColumnStochastic(double[][] matrix) {
+ validateMatrix(matrix);
+
+ int rows = matrix.length;
+ int cols = matrix[0].length;
+
+ for (int j = 0; j < cols; j++) {
+ double sum = 0.0;
+ for (int i = 0; i < rows; i++) {
+ if (matrix[i][j] < 0) {
+ return false;
+ }
+ sum += matrix[i][j];
+ }
+ if (Math.abs(sum - 1.0) > TOLERANCE) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static void validateMatrix(double[][] matrix) {
+ if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
+ throw new IllegalArgumentException("Matrix must not be null or empty");
+ }
+ }
+}
diff --git a/src/test/java/com/thealgorithms/matrix/StochasticMatrixTest.java b/src/test/java/com/thealgorithms/matrix/StochasticMatrixTest.java
new file mode 100644
index 000000000000..1bba918dadac
--- /dev/null
+++ b/src/test/java/com/thealgorithms/matrix/StochasticMatrixTest.java
@@ -0,0 +1,28 @@
+package com.thealgorithms.matrix;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+class StochasticMatrixTest {
+
+ @Test
+ void testRowStochasticMatrix() {
+ double[][] matrix = {{0.2, 0.5, 0.3}, {0.1, 0.6, 0.3}};
+ assertTrue(StochasticMatrix.isRowStochastic(matrix));
+ assertFalse(StochasticMatrix.isColumnStochastic(matrix));
+ }
+
+ @Test
+ void testColumnStochasticMatrix() {
+ double[][] matrix = {{0.4, 0.2}, {0.6, 0.8}};
+ assertTrue(StochasticMatrix.isColumnStochastic(matrix));
+ }
+
+ @Test
+ void testInvalidMatrix() {
+ double[][] matrix = {{0.5, -0.5}, {0.5, 1.5}};
+ assertFalse(StochasticMatrix.isRowStochastic(matrix));
+ }
+}
From 35556fe1f14d24f901d37bb7dcab6ad3faf75a91 Mon Sep 17 00:00:00 2001
From: Patil Arpita
Date: Mon, 29 Dec 2025 18:57:31 +0530
Subject: [PATCH 209/272] Added 0/1 Knapsack Algorithm using Dynamic
Programming in Java (#6789)
* Added 0/1 Knapsack Algorithm using Dynamic Programming in Java
* Fix Checkstyle whitespace issues in Knapsack.java
* Formatted Knapsack.java to pass linter and added 0/1 Knapsack algorithm
* Formatted Knapsack.java to pass linter and added 0/1 Knapsack algorithm
* Formatted Knapsack.java to pass linter and added 0/1 Knapsack algorithm
* Formatted Knapsack.java to pass linter and added 0/1 Knapsack algorithm
---------
Co-authored-by: Deniz Altunkapan
---
.../dynamicprogramming/Knapsack.java | 59 +++++++++++++------
1 file changed, 41 insertions(+), 18 deletions(-)
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/Knapsack.java b/src/main/java/com/thealgorithms/dynamicprogramming/Knapsack.java
index 134561766830..0d4c8d501f9f 100644
--- a/src/main/java/com/thealgorithms/dynamicprogramming/Knapsack.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/Knapsack.java
@@ -3,53 +3,76 @@
import java.util.Arrays;
/**
- * A Dynamic Programming based solution for the 0-1 Knapsack problem.
- * This class provides a method, `knapSack`, that calculates the maximum value that can be
- * obtained from a given set of items with weights and values, while not exceeding a
- * given weight capacity.
+ * 0/1 Knapsack Problem - Dynamic Programming solution.
*
- * @see 0-1 Knapsack Problem
+ * This algorithm solves the classic optimization problem where we have n items,
+ * each with a weight and a value. The goal is to maximize the total value
+ * without exceeding the knapsack's weight capacity.
+ *
+ * Time Complexity: O(n * W)
+ * Space Complexity: O(W)
+ *
+ * Example:
+ * values = {60, 100, 120}
+ * weights = {10, 20, 30}
+ * W = 50
+ * Output: 220
+ *
+ * @author Arpita
+ * @see Knapsack Problem
*/
public final class Knapsack {
private Knapsack() {
}
+ /**
+ * Validates the input to ensure correct constraints.
+ */
private static void throwIfInvalidInput(final int weightCapacity, final int[] weights, final int[] values) {
if (weightCapacity < 0) {
throw new IllegalArgumentException("Weight capacity should not be negative.");
}
if (weights == null || values == null || weights.length != values.length) {
- throw new IllegalArgumentException("Input arrays must not be null and must have the same length.");
+ throw new IllegalArgumentException("Weights and values must be non-null and of the same length.");
}
if (Arrays.stream(weights).anyMatch(w -> w <= 0)) {
- throw new IllegalArgumentException("Input array should not contain non-positive weight(s).");
+ throw new IllegalArgumentException("Weights must be positive.");
}
}
/**
- * Solves the 0-1 Knapsack problem using Dynamic Programming.
+ * Solves the 0/1 Knapsack problem using Dynamic Programming (bottom-up approach).
*
* @param weightCapacity The maximum weight capacity of the knapsack.
- * @param weights An array of item weights.
- * @param values An array of item values.
- * @return The maximum value that can be obtained without exceeding the weight capacity.
- * @throws IllegalArgumentException If the input arrays are null or have different lengths.
+ * @param weights The array of item weights.
+ * @param values The array of item values.
+ * @return The maximum total value achievable without exceeding capacity.
*/
- public static int knapSack(final int weightCapacity, final int[] weights, final int[] values) throws IllegalArgumentException {
+ public static int knapSack(final int weightCapacity, final int[] weights, final int[] values) {
throwIfInvalidInput(weightCapacity, weights, values);
- // DP table to store the state of the maximum possible return for a given weight capacity.
int[] dp = new int[weightCapacity + 1];
+ // Fill dp[] array iteratively
for (int i = 0; i < values.length; i++) {
- for (int w = weightCapacity; w > 0; w--) {
- if (weights[i] <= w) {
- dp[w] = Math.max(dp[w], dp[w - weights[i]] + values[i]);
- }
+ for (int w = weightCapacity; w >= weights[i]; w--) {
+ dp[w] = Math.max(dp[w], dp[w - weights[i]] + values[i]);
}
}
return dp[weightCapacity];
}
+
+ /*
+ // Example main method for local testing only.
+ public static void main(String[] args) {
+ int[] values = {60, 100, 120};
+ int[] weights = {10, 20, 30};
+ int weightCapacity = 50;
+
+ int maxValue = knapSack(weightCapacity, weights, values);
+ System.out.println("Maximum value = " + maxValue); // Output: 220
+ }
+ */
}
From 6149ec7fed62c68d0ac6e0e91f9e9125d43bf385 Mon Sep 17 00:00:00 2001
From: Deniz Altunkapan
Date: Mon, 29 Dec 2025 16:06:23 +0100
Subject: [PATCH 210/272] Update DIRECTORY.md (#7093)
Co-authored-by: DenizAltunkapan
---
DIRECTORY.md | 35 +++++++++++++++++++++++++++++++++--
1 file changed, 33 insertions(+), 2 deletions(-)
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 6ea83fc6a60a..deaf59636fa4 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -80,6 +80,7 @@
- 📄 [ECC](src/main/java/com/thealgorithms/ciphers/ECC.java)
- 📄 [HillCipher](src/main/java/com/thealgorithms/ciphers/HillCipher.java)
- 📄 [MonoAlphabetic](src/main/java/com/thealgorithms/ciphers/MonoAlphabetic.java)
+ - 📄 [OneTimePadCipher](src/main/java/com/thealgorithms/ciphers/OneTimePadCipher.java)
- 📄 [PermutationCipher](src/main/java/com/thealgorithms/ciphers/PermutationCipher.java)
- 📄 [PlayfairCipher](src/main/java/com/thealgorithms/ciphers/PlayfairCipher.java)
- 📄 [Polybius](src/main/java/com/thealgorithms/ciphers/Polybius.java)
@@ -200,6 +201,7 @@
- 📄 [GenericHashMapUsingArrayList](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayList.java)
- 📄 [HashMap](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/HashMap.java)
- 📄 [HashMapCuckooHashing](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/HashMapCuckooHashing.java)
+ - 📄 [ImmutableHashMap](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/ImmutableHashMap.java)
- 📄 [Intersection](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/Intersection.java)
- 📄 [LinearProbingHashMap](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMap.java)
- 📄 [MainCuckooHashing](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/MainCuckooHashing.java)
@@ -266,8 +268,10 @@
- 📄 [BSTRecursiveGeneric](src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java)
- 📄 [BTree](src/main/java/com/thealgorithms/datastructures/trees/BTree.java)
- 📄 [BinaryTree](src/main/java/com/thealgorithms/datastructures/trees/BinaryTree.java)
+ - 📄 [BinaryTreeToString](src/main/java/com/thealgorithms/datastructures/trees/BinaryTreeToString.java)
- 📄 [BoundaryTraversal](src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java)
- 📄 [CeilInBinarySearchTree](src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.java)
+ - 📄 [CentroidDecomposition](src/main/java/com/thealgorithms/datastructures/trees/CentroidDecomposition.java)
- 📄 [CheckBinaryTreeIsValidBST](src/main/java/com/thealgorithms/datastructures/trees/CheckBinaryTreeIsValidBST.java)
- 📄 [CheckIfBinaryTreeBalanced](src/main/java/com/thealgorithms/datastructures/trees/CheckIfBinaryTreeBalanced.java)
- 📄 [CheckTreeIsSymmetric](src/main/java/com/thealgorithms/datastructures/trees/CheckTreeIsSymmetric.java)
@@ -287,6 +291,7 @@
- 📄 [SameTreesCheck](src/main/java/com/thealgorithms/datastructures/trees/SameTreesCheck.java)
- 📄 [SegmentTree](src/main/java/com/thealgorithms/datastructures/trees/SegmentTree.java)
- 📄 [SplayTree](src/main/java/com/thealgorithms/datastructures/trees/SplayTree.java)
+ - 📄 [ThreadedBinaryTree](src/main/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTree.java)
- 📄 [Treap](src/main/java/com/thealgorithms/datastructures/trees/Treap.java)
- 📄 [TreeRandomNode](src/main/java/com/thealgorithms/datastructures/trees/TreeRandomNode.java)
- 📄 [Trie](src/main/java/com/thealgorithms/datastructures/trees/Trie.java)
@@ -426,6 +431,7 @@
- 📄 [AbsoluteMax](src/main/java/com/thealgorithms/maths/AbsoluteMax.java)
- 📄 [AbsoluteMin](src/main/java/com/thealgorithms/maths/AbsoluteMin.java)
- 📄 [AbsoluteValue](src/main/java/com/thealgorithms/maths/AbsoluteValue.java)
+ - 📄 [AbundantNumber](src/main/java/com/thealgorithms/maths/AbundantNumber.java)
- 📄 [AliquotSum](src/main/java/com/thealgorithms/maths/AliquotSum.java)
- 📄 [AmicableNumber](src/main/java/com/thealgorithms/maths/AmicableNumber.java)
- 📄 [Area](src/main/java/com/thealgorithms/maths/Area.java)
@@ -452,10 +458,11 @@
- 📄 [EulerMethod](src/main/java/com/thealgorithms/maths/EulerMethod.java)
- 📄 [EulerPseudoprime](src/main/java/com/thealgorithms/maths/EulerPseudoprime.java)
- 📄 [EulersFunction](src/main/java/com/thealgorithms/maths/EulersFunction.java)
+ - 📄 [EvilNumber](src/main/java/com/thealgorithms/maths/EvilNumber.java)
+ - 📄 [ExtendedEuclideanAlgorithm](src/main/java/com/thealgorithms/maths/ExtendedEuclideanAlgorithm.java)
- 📄 [FFT](src/main/java/com/thealgorithms/maths/FFT.java)
- 📄 [FFTBluestein](src/main/java/com/thealgorithms/maths/FFTBluestein.java)
- 📄 [Factorial](src/main/java/com/thealgorithms/maths/Factorial.java)
- - 📄 [FactorialRecursion](src/main/java/com/thealgorithms/maths/FactorialRecursion.java)
- 📄 [FastExponentiation](src/main/java/com/thealgorithms/maths/FastExponentiation.java)
- 📄 [FastInverseSqrt](src/main/java/com/thealgorithms/maths/FastInverseSqrt.java)
- 📄 [FibonacciJavaStreams](src/main/java/com/thealgorithms/maths/FibonacciJavaStreams.java)
@@ -489,6 +496,7 @@
- 📄 [LinearDiophantineEquationsSolver](src/main/java/com/thealgorithms/maths/LinearDiophantineEquationsSolver.java)
- 📄 [LongDivision](src/main/java/com/thealgorithms/maths/LongDivision.java)
- 📄 [LucasSeries](src/main/java/com/thealgorithms/maths/LucasSeries.java)
+ - 📄 [LuckyNumber](src/main/java/com/thealgorithms/maths/LuckyNumber.java)
- 📄 [MagicSquare](src/main/java/com/thealgorithms/maths/MagicSquare.java)
- 📄 [MathBuilder](src/main/java/com/thealgorithms/maths/MathBuilder.java)
- 📄 [MaxValue](src/main/java/com/thealgorithms/maths/MaxValue.java)
@@ -561,6 +569,7 @@
- 📄 [PrintAMatrixInSpiralOrder](src/main/java/com/thealgorithms/matrix/PrintAMatrixInSpiralOrder.java)
- 📄 [RotateMatrixBy90Degrees](src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java)
- 📄 [SolveSystem](src/main/java/com/thealgorithms/matrix/SolveSystem.java)
+ - 📄 [StochasticMatrix](src/main/java/com/thealgorithms/matrix/StochasticMatrix.java)
- 📁 **matrixexponentiation**
- 📄 [Fibonacci](src/main/java/com/thealgorithms/matrix/matrixexponentiation/Fibonacci.java)
- 📁 **utils**
@@ -628,6 +637,8 @@
- 📄 [Kinematics](src/main/java/com/thealgorithms/physics/Kinematics.java)
- 📄 [ProjectileMotion](src/main/java/com/thealgorithms/physics/ProjectileMotion.java)
- 📄 [SimplePendulumRK4](src/main/java/com/thealgorithms/physics/SimplePendulumRK4.java)
+ - 📄 [SnellLaw](src/main/java/com/thealgorithms/physics/SnellLaw.java)
+ - 📄 [ThinLens](src/main/java/com/thealgorithms/physics/ThinLens.java)
- 📁 **puzzlesandgames**
- 📄 [TowerOfHanoi](src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java)
- 📄 [WordBoggle](src/main/java/com/thealgorithms/puzzlesandgames/WordBoggle.java)
@@ -640,6 +651,7 @@
- 📄 [ReservoirSampling](src/main/java/com/thealgorithms/randomized/ReservoirSampling.java)
- 📁 **recursion**
- 📄 [DiceThrower](src/main/java/com/thealgorithms/recursion/DiceThrower.java)
+ - 📄 [FactorialRecursion](src/main/java/com/thealgorithms/recursion/FactorialRecursion.java)
- 📄 [FibonacciSeries](src/main/java/com/thealgorithms/recursion/FibonacciSeries.java)
- 📄 [GenerateSubsets](src/main/java/com/thealgorithms/recursion/GenerateSubsets.java)
- 📄 [SylvesterSequence](src/main/java/com/thealgorithms/recursion/SylvesterSequence.java)
@@ -786,6 +798,7 @@
- 📄 [StackPostfixNotation](src/main/java/com/thealgorithms/stacks/StackPostfixNotation.java)
- 📄 [StackUsingTwoQueues](src/main/java/com/thealgorithms/stacks/StackUsingTwoQueues.java)
- 📄 [TrappingRainwater](src/main/java/com/thealgorithms/stacks/TrappingRainwater.java)
+ - 📄 [ValidParentheses](src/main/java/com/thealgorithms/stacks/ValidParentheses.java)
- 📁 **strings**
- 📄 [AhoCorasick](src/main/java/com/thealgorithms/strings/AhoCorasick.java)
- 📄 [Alphabetical](src/main/java/com/thealgorithms/strings/Alphabetical.java)
@@ -800,6 +813,7 @@
- 📄 [Isogram](src/main/java/com/thealgorithms/strings/Isogram.java)
- 📄 [Isomorphic](src/main/java/com/thealgorithms/strings/Isomorphic.java)
- 📄 [KMP](src/main/java/com/thealgorithms/strings/KMP.java)
+ - 📄 [LengthOfLastWord](src/main/java/com/thealgorithms/strings/LengthOfLastWord.java)
- 📄 [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)
@@ -904,6 +918,7 @@
- 📄 [ECCTest](src/test/java/com/thealgorithms/ciphers/ECCTest.java)
- 📄 [HillCipherTest](src/test/java/com/thealgorithms/ciphers/HillCipherTest.java)
- 📄 [MonoAlphabeticTest](src/test/java/com/thealgorithms/ciphers/MonoAlphabeticTest.java)
+ - 📄 [OneTimePadCipherTest](src/test/java/com/thealgorithms/ciphers/OneTimePadCipherTest.java)
- 📄 [PermutationCipherTest](src/test/java/com/thealgorithms/ciphers/PermutationCipherTest.java)
- 📄 [PlayfairTest](src/test/java/com/thealgorithms/ciphers/PlayfairTest.java)
- 📄 [PolybiusTest](src/test/java/com/thealgorithms/ciphers/PolybiusTest.java)
@@ -987,8 +1002,10 @@
- 📄 [DynamicArrayTest](src/test/java/com/thealgorithms/datastructures/dynamicarray/DynamicArrayTest.java)
- 📁 **graphs**
- 📄 [AStarTest](src/test/java/com/thealgorithms/datastructures/graphs/AStarTest.java)
+ - 📄 [BellmanFordTest](src/test/java/com/thealgorithms/datastructures/graphs/BellmanFordTest.java)
- 📄 [BipartiteGraphDFSTest](src/test/java/com/thealgorithms/datastructures/graphs/BipartiteGraphDFSTest.java)
- 📄 [BoruvkaAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/BoruvkaAlgorithmTest.java)
+ - 📄 [ConnectedComponentTest](src/test/java/com/thealgorithms/datastructures/graphs/ConnectedComponentTest.java)
- 📄 [DialsAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/DialsAlgorithmTest.java)
- 📄 [DijkstraAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java)
- 📄 [DijkstraOptimizedAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/DijkstraOptimizedAlgorithmTest.java)
@@ -1011,6 +1028,7 @@
- 📄 [GenericHashMapUsingArrayTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayTest.java)
- 📄 [HashMapCuckooHashingTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/HashMapCuckooHashingTest.java)
- 📄 [HashMapTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/HashMapTest.java)
+ - 📄 [ImmutableHashMapTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/ImmutableHashMapTest.java)
- 📄 [IntersectionTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/IntersectionTest.java)
- 📄 [LinearProbingHashMapTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMapTest.java)
- 📄 [MajorityElementTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/MajorityElementTest.java)
@@ -1069,8 +1087,10 @@
- 📄 [BSTRecursiveTest](src/test/java/com/thealgorithms/datastructures/trees/BSTRecursiveTest.java)
- 📄 [BTreeTest](src/test/java/com/thealgorithms/datastructures/trees/BTreeTest.java)
- 📄 [BinaryTreeTest](src/test/java/com/thealgorithms/datastructures/trees/BinaryTreeTest.java)
+ - 📄 [BinaryTreeToStringTest](src/test/java/com/thealgorithms/datastructures/trees/BinaryTreeToStringTest.java)
- 📄 [BoundaryTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java)
- 📄 [CeilInBinarySearchTreeTest](src/test/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTreeTest.java)
+ - 📄 [CentroidDecompositionTest](src/test/java/com/thealgorithms/datastructures/trees/CentroidDecompositionTest.java)
- 📄 [CheckBinaryTreeIsValidBSTTest](src/test/java/com/thealgorithms/datastructures/trees/CheckBinaryTreeIsValidBSTTest.java)
- 📄 [CheckIfBinaryTreeBalancedTest](src/test/java/com/thealgorithms/datastructures/trees/CheckIfBinaryTreeBalancedTest.java)
- 📄 [CheckTreeIsSymmetricTest](src/test/java/com/thealgorithms/datastructures/trees/CheckTreeIsSymmetricTest.java)
@@ -1084,6 +1104,7 @@
- 📄 [QuadTreeTest](src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java)
- 📄 [SameTreesCheckTest](src/test/java/com/thealgorithms/datastructures/trees/SameTreesCheckTest.java)
- 📄 [SplayTreeTest](src/test/java/com/thealgorithms/datastructures/trees/SplayTreeTest.java)
+ - 📄 [ThreadedBinaryTreeTest](src/test/java/com/thealgorithms/datastructures/trees/ThreadedBinaryTreeTest.java)
- 📄 [TreapTest](src/test/java/com/thealgorithms/datastructures/trees/TreapTest.java)
- 📄 [TreeTestUtils](src/test/java/com/thealgorithms/datastructures/trees/TreeTestUtils.java)
- 📄 [TrieTest](src/test/java/com/thealgorithms/datastructures/trees/TrieTest.java)
@@ -1171,6 +1192,7 @@
- 📄 [DinicTest](src/test/java/com/thealgorithms/graph/DinicTest.java)
- 📄 [EdmondsKarpTest](src/test/java/com/thealgorithms/graph/EdmondsKarpTest.java)
- 📄 [EdmondsTest](src/test/java/com/thealgorithms/graph/EdmondsTest.java)
+ - 📄 [GomoryHuTreeTest](src/test/java/com/thealgorithms/graph/GomoryHuTreeTest.java)
- 📄 [HierholzerAlgorithmTest](src/test/java/com/thealgorithms/graph/HierholzerAlgorithmTest.java)
- 📄 [HierholzerEulerianPathTest](src/test/java/com/thealgorithms/graph/HierholzerEulerianPathTest.java)
- 📄 [HopcroftKarpTest](src/test/java/com/thealgorithms/graph/HopcroftKarpTest.java)
@@ -1208,6 +1230,7 @@
- 📄 [AbsoluteMaxTest](src/test/java/com/thealgorithms/maths/AbsoluteMaxTest.java)
- 📄 [AbsoluteMinTest](src/test/java/com/thealgorithms/maths/AbsoluteMinTest.java)
- 📄 [AbsoluteValueTest](src/test/java/com/thealgorithms/maths/AbsoluteValueTest.java)
+ - 📄 [AbundantNumberTest](src/test/java/com/thealgorithms/maths/AbundantNumberTest.java)
- 📄 [AliquotSumTest](src/test/java/com/thealgorithms/maths/AliquotSumTest.java)
- 📄 [AmicableNumberTest](src/test/java/com/thealgorithms/maths/AmicableNumberTest.java)
- 📄 [AreaTest](src/test/java/com/thealgorithms/maths/AreaTest.java)
@@ -1233,8 +1256,9 @@
- 📄 [EulerMethodTest](src/test/java/com/thealgorithms/maths/EulerMethodTest.java)
- 📄 [EulerPseudoprimeTest](src/test/java/com/thealgorithms/maths/EulerPseudoprimeTest.java)
- 📄 [EulersFunctionTest](src/test/java/com/thealgorithms/maths/EulersFunctionTest.java)
+ - 📄 [EvilNumberTest](src/test/java/com/thealgorithms/maths/EvilNumberTest.java)
+ - 📄 [ExtendedEuclideanAlgorithmTest](src/test/java/com/thealgorithms/maths/ExtendedEuclideanAlgorithmTest.java)
- 📄 [FFTTest](src/test/java/com/thealgorithms/maths/FFTTest.java)
- - 📄 [FactorialRecursionTest](src/test/java/com/thealgorithms/maths/FactorialRecursionTest.java)
- 📄 [FactorialTest](src/test/java/com/thealgorithms/maths/FactorialTest.java)
- 📄 [FastExponentiationTest](src/test/java/com/thealgorithms/maths/FastExponentiationTest.java)
- 📄 [FastInverseSqrtTests](src/test/java/com/thealgorithms/maths/FastInverseSqrtTests.java)
@@ -1269,6 +1293,7 @@
- 📄 [LinearDiophantineEquationsSolverTest](src/test/java/com/thealgorithms/maths/LinearDiophantineEquationsSolverTest.java)
- 📄 [LongDivisionTest](src/test/java/com/thealgorithms/maths/LongDivisionTest.java)
- 📄 [LucasSeriesTest](src/test/java/com/thealgorithms/maths/LucasSeriesTest.java)
+ - 📄 [LuckyNumberTest](src/test/java/com/thealgorithms/maths/LuckyNumberTest.java)
- 📄 [MathBuilderTest](src/test/java/com/thealgorithms/maths/MathBuilderTest.java)
- 📄 [MaxValueTest](src/test/java/com/thealgorithms/maths/MaxValueTest.java)
- 📄 [MeansTest](src/test/java/com/thealgorithms/maths/MeansTest.java)
@@ -1336,6 +1361,7 @@
- 📄 [MirrorOfMatrixTest](src/test/java/com/thealgorithms/matrix/MirrorOfMatrixTest.java)
- 📄 [PrintAMatrixInSpiralOrderTest](src/test/java/com/thealgorithms/matrix/PrintAMatrixInSpiralOrderTest.java)
- 📄 [SolveSystemTest](src/test/java/com/thealgorithms/matrix/SolveSystemTest.java)
+ - 📄 [StochasticMatrixTest](src/test/java/com/thealgorithms/matrix/StochasticMatrixTest.java)
- 📁 **misc**
- 📄 [ColorContrastRatioTest](src/test/java/com/thealgorithms/misc/ColorContrastRatioTest.java)
- 📄 [MapReduceTest](src/test/java/com/thealgorithms/misc/MapReduceTest.java)
@@ -1389,6 +1415,8 @@
- 📄 [KinematicsTest](src/test/java/com/thealgorithms/physics/KinematicsTest.java)
- 📄 [ProjectileMotionTest](src/test/java/com/thealgorithms/physics/ProjectileMotionTest.java)
- 📄 [SimplePendulumRK4Test](src/test/java/com/thealgorithms/physics/SimplePendulumRK4Test.java)
+ - 📄 [SnellLawTest](src/test/java/com/thealgorithms/physics/SnellLawTest.java)
+ - 📄 [ThinLensTest](src/test/java/com/thealgorithms/physics/ThinLensTest.java)
- 📁 **puzzlesandgames**
- 📄 [TowerOfHanoiTest](src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java)
- 📄 [WordBoggleTest](src/test/java/com/thealgorithms/puzzlesandgames/WordBoggleTest.java)
@@ -1401,6 +1429,7 @@
- 📄 [ReservoirSamplingTest](src/test/java/com/thealgorithms/randomized/ReservoirSamplingTest.java)
- 📁 **recursion**
- 📄 [DiceThrowerTest](src/test/java/com/thealgorithms/recursion/DiceThrowerTest.java)
+ - 📄 [FactorialRecursionTest](src/test/java/com/thealgorithms/recursion/FactorialRecursionTest.java)
- 📄 [FibonacciSeriesTest](src/test/java/com/thealgorithms/recursion/FibonacciSeriesTest.java)
- 📄 [GenerateSubsetsTest](src/test/java/com/thealgorithms/recursion/GenerateSubsetsTest.java)
- 📄 [SylvesterSequenceTest](src/test/java/com/thealgorithms/recursion/SylvesterSequenceTest.java)
@@ -1546,6 +1575,7 @@
- 📄 [StackPostfixNotationTest](src/test/java/com/thealgorithms/stacks/StackPostfixNotationTest.java)
- 📄 [StackUsingTwoQueuesTest](src/test/java/com/thealgorithms/stacks/StackUsingTwoQueuesTest.java)
- 📄 [TrappingRainwaterTest](src/test/java/com/thealgorithms/stacks/TrappingRainwaterTest.java)
+ - 📄 [ValidParenthesesTest](src/test/java/com/thealgorithms/stacks/ValidParenthesesTest.java)
- 📁 **strings**
- 📄 [AhoCorasickTest](src/test/java/com/thealgorithms/strings/AhoCorasickTest.java)
- 📄 [AlphabeticalTest](src/test/java/com/thealgorithms/strings/AlphabeticalTest.java)
@@ -1559,6 +1589,7 @@
- 📄 [HorspoolSearchTest](src/test/java/com/thealgorithms/strings/HorspoolSearchTest.java)
- 📄 [IsogramTest](src/test/java/com/thealgorithms/strings/IsogramTest.java)
- 📄 [IsomorphicTest](src/test/java/com/thealgorithms/strings/IsomorphicTest.java)
+ - 📄 [LengthOfLastWordTest](src/test/java/com/thealgorithms/strings/LengthOfLastWordTest.java)
- 📄 [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)
From 0eda2a1db81424206effd7159af191870ab3a842 Mon Sep 17 00:00:00 2001
From: Deniz Altunkapan
Date: Mon, 29 Dec 2025 21:55:23 +0100
Subject: [PATCH 211/272] Add test requirement to pull request template (#7185)
* Add checklist item for test class inclusion
* Update pull request template for algorithm tests
---
.github/pull_request_template.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index d9cc4c3c35c5..30b46bbf45b5 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -13,4 +13,5 @@ In order to reduce the number of notifications sent to the maintainers, please:
- [ ] All filenames are in PascalCase.
- [ ] All functions and variable names follow Java naming conventions.
- [ ] All new algorithms have a URL in their comments that points to Wikipedia or other similar explanations.
-- [ ] All new code is formatted with `clang-format -i --style=file path/to/your/file.java`
\ No newline at end of file
+- [ ] All new algorithms include a corresponding test class that validates their functionality.
+- [ ] All new code is formatted with `clang-format -i --style=file path/to/your/file.java`
From e945f1622490ff3b32e59d31780df27d0dc2ede4 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 1 Jan 2026 18:23:45 +0100
Subject: [PATCH 212/272] chore(deps): bump com.puppycrawl.tools:checkstyle
from 12.3.0 to 12.3.1 (#7188)
Bumps [com.puppycrawl.tools:checkstyle](https://github.com/checkstyle/checkstyle) from 12.3.0 to 12.3.1.
- [Release notes](https://github.com/checkstyle/checkstyle/releases)
- [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-12.3.0...checkstyle-12.3.1)
---
updated-dependencies:
- dependency-name: com.puppycrawl.tools:checkstyle
dependency-version: 12.3.1
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index d60f8b9668e6..59a497427c0d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -112,7 +112,7 @@
com.puppycrawl.tools
checkstyle
- 12.3.0
+ 12.3.1
From 24389c06a29c3472eb1e64c211a585eb5f9a0ff4 Mon Sep 17 00:00:00 2001
From: Giridharan S <168095425+S-GIRI@users.noreply.github.com>
Date: Mon, 5 Jan 2026 21:40:24 +0530
Subject: [PATCH 213/272] Add detailed JavaDoc for AllPathsFromSourceToTarget
algorithm (#7192)
Add detailed JavaDoc for AllPathsFromSourceToTarget
---
.../AllPathsFromSourceToTarget.java | 31 +++++++++++++++++--
1 file changed, 28 insertions(+), 3 deletions(-)
diff --git a/src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java b/src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java
index c35a36d97a57..269880b8ddae 100644
--- a/src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java
+++ b/src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java
@@ -4,11 +4,36 @@
import java.util.List;
/**
- * Program description - To find all possible paths from source to destination
- * Wikipedia
+ * Finds all possible simple paths from a given source vertex to a destination vertex
+ * in a directed graph using backtracking.
*
- * @author Siddhant Swarup Mallick
+ * This algorithm performs a Depth First Search (DFS) traversal while keeping track
+ * of visited vertices to avoid cycles. Whenever the destination vertex is reached,
+ * the current path is stored as one valid path.
+ *
+ * Key Characteristics:
+ *
+ * - Works on directed graphs
+ * - Does not allow revisiting vertices in the same path
+ * - Stores all possible paths from source to destination
+ *
+ *
+ * Time Complexity:
+ *
+ * - Worst Case: O(V!) — when the graph is fully connected
+ *
+ *
+ * Space Complexity:
+ *
+ * - O(V) for recursion stack and visited array
+ * - Additional space for storing all valid paths
+ *
+ *
+ * This implementation is intended for educational purposes.
+ *
+ * @see Depth First Search
*/
+
@SuppressWarnings({"rawtypes", "unchecked"})
public class AllPathsFromSourceToTarget {
From c06c0f03e3f8aa1390b866a1c9483e34c13fbda3 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 5 Jan 2026 22:50:29 +0100
Subject: [PATCH 214/272] chore(deps): bump com.puppycrawl.tools:checkstyle
from 12.3.1 to 13.0.0 (#7193)
Bumps [com.puppycrawl.tools:checkstyle](https://github.com/checkstyle/checkstyle) from 12.3.1 to 13.0.0.
- [Release notes](https://github.com/checkstyle/checkstyle/releases)
- [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-12.3.1...checkstyle-13.0.0)
---
updated-dependencies:
- dependency-name: com.puppycrawl.tools:checkstyle
dependency-version: 13.0.0
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 59a497427c0d..73869d6dd942 100644
--- a/pom.xml
+++ b/pom.xml
@@ -112,7 +112,7 @@
com.puppycrawl.tools
checkstyle
- 12.3.1
+ 13.0.0
From 404e1404aa6f97c711bf9beb3d54c78097b28357 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 6 Jan 2026 22:38:42 +0100
Subject: [PATCH 215/272] chore(deps): bump org.junit:junit-bom from 6.0.1 to
6.0.2 (#7194)
Bumps [org.junit:junit-bom](https://github.com/junit-team/junit-framework) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/junit-team/junit-framework/releases)
- [Commits](https://github.com/junit-team/junit-framework/compare/r6.0.1...r6.0.2)
---
updated-dependencies:
- dependency-name: org.junit:junit-bom
dependency-version: 6.0.2
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 73869d6dd942..d3db730327d3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,7 +20,7 @@
org.junit
junit-bom
- 6.0.1
+ 6.0.2
pom
import
From 938d06abb5f6a15ffadd260e1810f1a502679561 Mon Sep 17 00:00:00 2001
From: Rajesh Reddy
Date: Wed, 7 Jan 2026 17:19:51 +0530
Subject: [PATCH 216/272] docs: clarify hash map vs HashMap terminology (#7195)
---
.../java/com/thealgorithms/datastructures/hashmap/Readme.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/main/java/com/thealgorithms/datastructures/hashmap/Readme.md b/src/main/java/com/thealgorithms/datastructures/hashmap/Readme.md
index 252b06ea59b0..4400a97d8128 100644
--- a/src/main/java/com/thealgorithms/datastructures/hashmap/Readme.md
+++ b/src/main/java/com/thealgorithms/datastructures/hashmap/Readme.md
@@ -2,6 +2,8 @@
A hash map organizes data so you can quickly look up values for a given key.
+> Note: The term “hash map” refers to the data structure concept, while `HashMap` refers specifically to Java’s implementation.
+
## Strengths:
- **Fast lookups**: Lookups take O(1) time on average.
- **Flexible keys**: Most data types can be used for keys, as long as they're hashable.
From ca4bebcbd55edd9dd39e4115cf9c0d962f8c4944 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 8 Jan 2026 09:56:14 +0100
Subject: [PATCH 217/272] chore(deps): bump peter-evans/create-pull-request
from 7 to 8 in /.github/workflows (#7199)
chore(deps): bump peter-evans/create-pull-request in /.github/workflows
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 7 to 8.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](https://github.com/peter-evans/create-pull-request/compare/v7...v8)
---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
dependency-version: '8'
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.github/workflows/update-directorymd.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/update-directorymd.yml b/.github/workflows/update-directorymd.yml
index 101d82427e38..aa553b46a23b 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:
@@ -33,7 +33,7 @@ jobs:
git diff --cached --quiet || git commit -m "Update DIRECTORY.md"
- name: Create Pull Request
- uses: peter-evans/create-pull-request@v7
+ uses: peter-evans/create-pull-request@v8
with:
token: ${{ secrets.REPO_SCOPED_TOKEN }}
branch: update-directory
From fe6066b332d6e77f5f36292e9958dad367e0b731 Mon Sep 17 00:00:00 2001
From: Ahmed Allam <60698204+GziXnine@users.noreply.github.com>
Date: Fri, 9 Jan 2026 13:36:46 +0200
Subject: [PATCH 218/272] =?UTF-8?q?Add=20SmoothSort=20(Dijkstra=E2=80=99s?=
=?UTF-8?q?=20adaptive=20in-place=20heapsort=20variant)=20(#7200)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* feat: implement Smooth Sort algorithm with detailed JavaDoc and test class
* style: format LEONARDO array for improved readability with clang-format
---------
Co-authored-by: Ahmed Allam <60698204+AllamF5J@users.noreply.github.com>
---
.../com/thealgorithms/sorts/SmoothSort.java | 168 ++++++++++++++++++
.../thealgorithms/sorts/SmoothSortTest.java | 8 +
2 files changed, 176 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/sorts/SmoothSort.java
create mode 100644 src/test/java/com/thealgorithms/sorts/SmoothSortTest.java
diff --git a/src/main/java/com/thealgorithms/sorts/SmoothSort.java b/src/main/java/com/thealgorithms/sorts/SmoothSort.java
new file mode 100644
index 000000000000..c45d6f1f02b2
--- /dev/null
+++ b/src/main/java/com/thealgorithms/sorts/SmoothSort.java
@@ -0,0 +1,168 @@
+package com.thealgorithms.sorts;
+
+/**
+ * Smooth Sort is an in-place, comparison-based sorting algorithm proposed by Edsger W. Dijkstra (1981).
+ *
+ * It can be viewed as a variant of heapsort that maintains a forest of heap-ordered Leonardo trees
+ * (trees whose sizes are Leonardo numbers). The algorithm is adaptive: when the input is already
+ * sorted or nearly sorted, the heap invariants are often satisfied and the expensive rebalancing
+ * operations do little work, yielding near-linear behavior.
+ *
+ *
Time Complexity:
+ *
+ * - Best case: O(n) for already sorted input
+ * - Average case: O(n log n)
+ * - Worst case: O(n log n)
+ *
+ *
+ * Space Complexity: O(1) auxiliary space (in-place).
+ *
+ * @see Smoothsort
+ * @see Leonardo numbers
+ * @see SortAlgorithm
+ */
+public class SmoothSort implements SortAlgorithm {
+
+ /**
+ * Leonardo numbers (L(0) = L(1) = 1, L(k+2) = L(k+1) + L(k) + 1) up to the largest value that
+ * fits into a signed 32-bit integer.
+ */
+ private static final int[] LEONARDO = {1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, 48315633, 78176337,
+ 126491971, 204668309, 331160281, 535828591, 866988873, 1402817465};
+
+ /**
+ * Sorts the given array in ascending order using Smooth Sort.
+ *
+ * @param array the array to sort
+ * @param the element type
+ * @return the sorted array
+ */
+ @Override
+ public > T[] sort(final T[] array) {
+ if (array.length < 2) {
+ return array;
+ }
+
+ final int last = array.length - 1;
+
+ // The forest shape is encoded as (p, pshift): p is a bit-vector of present tree orders,
+ // shifted right by pshift. pshift is the order of the rightmost (current) Leonardo tree.
+ long p = 1L;
+ int pshift = 1;
+
+ int head = 0;
+ while (head < last) {
+ if ((p & 3L) == 3L) {
+ sift(array, pshift, head);
+ p >>>= 2;
+ pshift += 2;
+ } else {
+ // Add a new singleton tree; if it will not be merged anymore, we must fully trinkle.
+ if (LEONARDO[pshift - 1] >= last - head) {
+ trinkle(array, p, pshift, head, false);
+ } else {
+ // This tree will be merged later, so it is enough to restore its internal heap property.
+ sift(array, pshift, head);
+ }
+
+ if (pshift == 1) {
+ // If L(1) is used, the new singleton is L(0).
+ p <<= 1;
+ pshift = 0;
+ } else {
+ // Otherwise, shift to order 1 and append a singleton of order 1.
+ p <<= (pshift - 1);
+ pshift = 1;
+ }
+ }
+
+ p |= 1L;
+ head++;
+ }
+
+ trinkle(array, p, pshift, head, false);
+
+ // Repeatedly remove the maximum (always at head) by shrinking the heap region.
+ while (pshift != 1 || p != 1L) {
+ if (pshift <= 1) {
+ // Rightmost tree is a singleton (order 0 or 1). Move to the previous tree root.
+ final long mask = p & ~1L;
+ final int shift = Long.numberOfTrailingZeros(mask);
+ p >>>= shift;
+ pshift += shift;
+ } else {
+ // Split a tree of order (pshift) into two children trees of orders (pshift-1) and (pshift-2).
+ p <<= 2;
+ p ^= 7L;
+ pshift -= 2;
+
+ trinkle(array, p >>> 1, pshift + 1, head - LEONARDO[pshift] - 1, true);
+ trinkle(array, p, pshift, head - 1, true);
+ }
+
+ head--;
+ }
+
+ return array;
+ }
+
+ private static > void sift(final T[] array, int order, int root) {
+ final T value = array[root];
+
+ while (order > 1) {
+ final int right = root - 1;
+ final int left = root - 1 - LEONARDO[order - 2];
+
+ if (!SortUtils.less(value, array[left]) && !SortUtils.less(value, array[right])) {
+ break;
+ }
+
+ if (!SortUtils.less(array[left], array[right])) {
+ array[root] = array[left];
+ root = left;
+ order -= 1;
+ } else {
+ array[root] = array[right];
+ root = right;
+ order -= 2;
+ }
+ }
+
+ array[root] = value;
+ }
+
+ private static > void trinkle(final T[] array, long p, int order, int root, boolean trusty) {
+ final T value = array[root];
+
+ while (p != 1L) {
+ final int stepson = root - LEONARDO[order];
+
+ if (!SortUtils.less(value, array[stepson])) {
+ break;
+ }
+
+ if (!trusty && order > 1) {
+ final int right = root - 1;
+ final int left = root - 1 - LEONARDO[order - 2];
+
+ if (!SortUtils.less(array[right], array[stepson]) || !SortUtils.less(array[left], array[stepson])) {
+ break;
+ }
+ }
+
+ array[root] = array[stepson];
+ root = stepson;
+
+ final long mask = p & ~1L;
+ final int shift = Long.numberOfTrailingZeros(mask);
+ p >>>= shift;
+ order += shift;
+ trusty = false;
+ }
+
+ if (!trusty) {
+ array[root] = value;
+ sift(array, order, root);
+ }
+ }
+}
diff --git a/src/test/java/com/thealgorithms/sorts/SmoothSortTest.java b/src/test/java/com/thealgorithms/sorts/SmoothSortTest.java
new file mode 100644
index 000000000000..8df0502e80e7
--- /dev/null
+++ b/src/test/java/com/thealgorithms/sorts/SmoothSortTest.java
@@ -0,0 +1,8 @@
+package com.thealgorithms.sorts;
+
+public class SmoothSortTest extends SortingAlgorithmTest {
+ @Override
+ SortAlgorithm getSortAlgorithm() {
+ return new SmoothSort();
+ }
+}
From 1644db2a3449d3a82dfd96ad25a98d7489adcf54 Mon Sep 17 00:00:00 2001
From: Tarunj Gupta <145449390+tarunjgupta@users.noreply.github.com>
Date: Sat, 10 Jan 2026 21:02:19 +0530
Subject: [PATCH 219/272] Add Count Nice Subarrays sliding using window
algorithm (#7206)
* Add Count Nice Subarrays sliding window algorithm
* Add detailed comments and reference to CountNiceSubarrays
* Fix clang-format issues in CountNiceSubarrays
* Added extra edge cases
* changes made
---
.../slidingwindow/CountNiceSubarrays.java | 99 +++++++++++++++++++
.../slidingwindow/CountNiceSubarraysTest.java | 55 +++++++++++
2 files changed, 154 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/slidingwindow/CountNiceSubarrays.java
create mode 100644 src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java
diff --git a/src/main/java/com/thealgorithms/slidingwindow/CountNiceSubarrays.java b/src/main/java/com/thealgorithms/slidingwindow/CountNiceSubarrays.java
new file mode 100644
index 000000000000..46f8deeb58dd
--- /dev/null
+++ b/src/main/java/com/thealgorithms/slidingwindow/CountNiceSubarrays.java
@@ -0,0 +1,99 @@
+package com.thealgorithms.slidingwindow;
+
+/**
+ * Counts the number of "nice subarrays".
+ * A nice subarray is a contiguous subarray that contains exactly k odd numbers.
+ *
+ * This implementation uses the sliding window technique.
+ *
+ * Reference:
+ * https://leetcode.com/problems/count-number-of-nice-subarrays/
+ *
+ * Time Complexity: O(n)
+ * Space Complexity: O(n)
+ */
+public final class CountNiceSubarrays {
+
+ // Private constructor to prevent instantiation
+ private CountNiceSubarrays() {
+ }
+
+ /**
+ * Returns the count of subarrays containing exactly k odd numbers.
+ *
+ * @param nums input array of integers
+ * @param k number of odd elements required in the subarray
+ * @return number of nice subarrays
+ */
+ public static int countNiceSubarrays(int[] nums, int k) {
+
+ int n = nums.length;
+
+ // Left pointer of the sliding window
+ int left = 0;
+
+ // Tracks number of odd elements in the current window
+ int oddCount = 0;
+
+ // Final answer: total number of nice subarrays
+ int result = 0;
+
+ /*
+ * memo[i] stores how many valid starting positions exist
+ * when the left pointer is at index i.
+ *
+ * This avoids recomputing the same values again.
+ */
+ int[] memo = new int[n];
+
+ // Right pointer moves forward to expand the window
+ for (int right = 0; right < n; right++) {
+
+ // If current element is odd, increment odd count
+ if ((nums[right] & 1) == 1) {
+ oddCount++;
+ }
+
+ /*
+ * If oddCount exceeds k, shrink the window from the left
+ * until oddCount becomes valid again.
+ */
+ if (oddCount > k) {
+ left += memo[left];
+ oddCount--;
+ }
+
+ /*
+ * When the window contains exactly k odd numbers,
+ * count all possible valid subarrays starting at `left`.
+ */
+ if (oddCount == k) {
+
+ /*
+ * If this left index hasn't been processed before,
+ * count how many consecutive even numbers follow it.
+ */
+ if (memo[left] == 0) {
+ int count = 0;
+ int temp = left;
+
+ // Count consecutive even numbers
+ while ((nums[temp] & 1) == 0) {
+ count++;
+ temp++;
+ }
+
+ /*
+ * Number of valid subarrays starting at `left`
+ * is (count of even numbers + 1)
+ */
+ memo[left] = count + 1;
+ }
+
+ // Add number of valid subarrays for this left position
+ result += memo[left];
+ }
+ }
+ return result;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java b/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java
new file mode 100644
index 000000000000..71bf24cc9e30
--- /dev/null
+++ b/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java
@@ -0,0 +1,55 @@
+package com.thealgorithms.slidingwindow;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class CountNiceSubarraysTest {
+ @Test
+ void testExampleCase() {
+ int[] nums = {1, 1, 2, 1, 1};
+ assertEquals(2, CountNiceSubarrays.countNiceSubarrays(nums, 3));
+ }
+
+ @Test
+ void testAllEvenNumbers() {
+ int[] nums = {2, 4, 6, 8};
+ assertEquals(0, CountNiceSubarrays.countNiceSubarrays(nums, 1));
+ }
+
+ @Test
+ void testSingleOdd() {
+ int[] nums = {1};
+ assertEquals(1, CountNiceSubarrays.countNiceSubarrays(nums, 1));
+ }
+
+ @Test
+ void testMultipleChoices() {
+ int[] nums = {2, 2, 1, 2, 2, 1, 2};
+ assertEquals(6, CountNiceSubarrays.countNiceSubarrays(nums, 2));
+ }
+
+ @Test
+ void testTrailingEvenNumbers() {
+ int[] nums = {1, 2, 2, 2};
+ assertEquals(4, CountNiceSubarrays.countNiceSubarrays(nums, 1));
+ }
+
+ @Test
+ void testMultipleWindowShrinks() {
+ int[] nums = {1, 1, 1, 1};
+ assertEquals(3, CountNiceSubarrays.countNiceSubarrays(nums, 2));
+ }
+
+ @Test
+ void testEvensBetweenOdds() {
+ int[] nums = {2, 1, 2, 1, 2};
+ assertEquals(4, CountNiceSubarrays.countNiceSubarrays(nums, 2));
+ }
+
+ @Test
+ void testShrinkWithTrailingEvens() {
+ int[] nums = {2, 2, 1, 2, 2, 1, 2, 2};
+ assertEquals(9, CountNiceSubarrays.countNiceSubarrays(nums, 2));
+ }
+}
From bdda4fa6b49c94087caab1021d680aa78a50d7e1 Mon Sep 17 00:00:00 2001
From: asmitha-16
Date: Wed, 14 Jan 2026 03:09:41 +0530
Subject: [PATCH 220/272] Handle negative input in perfect square checks
(#7207)
---
src/main/java/com/thealgorithms/maths/PerfectSquare.java | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/main/java/com/thealgorithms/maths/PerfectSquare.java b/src/main/java/com/thealgorithms/maths/PerfectSquare.java
index e9318bd7d805..aec43062121a 100644
--- a/src/main/java/com/thealgorithms/maths/PerfectSquare.java
+++ b/src/main/java/com/thealgorithms/maths/PerfectSquare.java
@@ -15,6 +15,9 @@ private PerfectSquare() {
* false
*/
public static boolean isPerfectSquare(final int number) {
+ if (number < 0) {
+ return false;
+ }
final int sqrt = (int) Math.sqrt(number);
return sqrt * sqrt == number;
}
@@ -27,6 +30,9 @@ public static boolean isPerfectSquare(final int number) {
* {@code false}
*/
public static boolean isPerfectSquareUsingPow(long number) {
+ if (number < 0) {
+ return false;
+ }
long a = (long) Math.pow(number, 1.0 / 2);
return a * a == number;
}
From 7148661e44bb4b27d29f63771ef205235f42192a Mon Sep 17 00:00:00 2001
From: Ahmed Allam <60698204+GziXnine@users.noreply.github.com>
Date: Wed, 14 Jan 2026 00:04:14 +0200
Subject: [PATCH 221/272] Feat/tournament sort (#7201)
* feat: implement Smooth Sort algorithm with detailed JavaDoc and test class
* style: format LEONARDO array for improved readability with clang-format
* feat(sorts): add TournamentSort (winner-tree)
* test: add unit test for null array handling in TournamentSort
---------
Co-authored-by: Ahmed Allam <60698204+AllamF5J@users.noreply.github.com>
Co-authored-by: Deniz Altunkapan
Co-authored-by: Oleksandr Klymenko <19151554+alxkm@users.noreply.github.com>
---
.../thealgorithms/sorts/TournamentSort.java | 84 +++++++++++++++++++
.../sorts/TournamentSortTest.java | 19 +++++
2 files changed, 103 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/sorts/TournamentSort.java
create mode 100644 src/test/java/com/thealgorithms/sorts/TournamentSortTest.java
diff --git a/src/main/java/com/thealgorithms/sorts/TournamentSort.java b/src/main/java/com/thealgorithms/sorts/TournamentSort.java
new file mode 100644
index 000000000000..ec51a1e2c0a9
--- /dev/null
+++ b/src/main/java/com/thealgorithms/sorts/TournamentSort.java
@@ -0,0 +1,84 @@
+package com.thealgorithms.sorts;
+
+import java.util.Arrays;
+
+/**
+ * Tournament Sort algorithm implementation.
+ *
+ * Tournament sort builds a winner tree (a complete binary tree storing the index
+ * of the smallest element in each subtree). It then repeatedly extracts the
+ * winner (minimum) and updates the path from the removed leaf to the root.
+ *
+ * Time Complexity:
+ * - Best case: O(n log n)
+ * - Average case: O(n log n)
+ * - Worst case: O(n log n)
+ *
+ * Space Complexity: O(n) – additional winner-tree storage
+ *
+ * @see Tournament Sort Algorithm
+ * @see SortAlgorithm
+ */
+public class TournamentSort implements SortAlgorithm {
+
+ @Override
+ public > T[] sort(T[] array) {
+ if (array == null || array.length < 2) {
+ return array;
+ }
+
+ final int n = array.length;
+ final int leafCount = nextPowerOfTwo(n);
+
+ // Winner tree represented as an array:
+ // - Leaves live at [leafCount .. 2*leafCount)
+ // - Internal nodes live at [1 .. leafCount)
+ // Each node stores an index into the original array or -1 for "empty".
+ final int[] tree = new int[2 * leafCount];
+ Arrays.fill(tree, -1);
+
+ for (int i = 0; i < n; i++) {
+ tree[leafCount + i] = i;
+ }
+
+ for (int node = leafCount - 1; node >= 1; node--) {
+ tree[node] = winnerIndex(array, tree[node * 2], tree[node * 2 + 1]);
+ }
+
+ final T[] result = array.clone();
+ for (int out = 0; out < n; out++) {
+ final int winner = tree[1];
+ result[out] = array[winner];
+
+ int node = leafCount + winner;
+ tree[node] = -1;
+
+ for (node /= 2; node >= 1; node /= 2) {
+ tree[node] = winnerIndex(array, tree[node * 2], tree[node * 2 + 1]);
+ }
+ }
+
+ System.arraycopy(result, 0, array, 0, n);
+ return array;
+ }
+
+ private static int nextPowerOfTwo(int n) {
+ int power = 1;
+ while (power < n) {
+ power <<= 1;
+ }
+ return power;
+ }
+
+ private static > int winnerIndex(T[] array, int leftIndex, int rightIndex) {
+ if (leftIndex == -1) {
+ return rightIndex;
+ }
+ if (rightIndex == -1) {
+ return leftIndex;
+ }
+
+ // If equal, prefer the left element to keep ordering deterministic.
+ return SortUtils.less(array[rightIndex], array[leftIndex]) ? rightIndex : leftIndex;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/sorts/TournamentSortTest.java b/src/test/java/com/thealgorithms/sorts/TournamentSortTest.java
new file mode 100644
index 000000000000..91da746447a8
--- /dev/null
+++ b/src/test/java/com/thealgorithms/sorts/TournamentSortTest.java
@@ -0,0 +1,19 @@
+package com.thealgorithms.sorts;
+
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.Test;
+
+public class TournamentSortTest extends SortingAlgorithmTest {
+
+ @Test
+ void shouldAcceptWhenNullArrayIsPassed() {
+ Integer[] array = null;
+ assertNull(getSortAlgorithm().sort(array));
+ }
+
+ @Override
+ SortAlgorithm getSortAlgorithm() {
+ return new TournamentSort();
+ }
+}
From 66f76eb3d920f7a025aaca71ccc6c84da4287658 Mon Sep 17 00:00:00 2001
From: Ahmed Allam <60698204+GziXnine@users.noreply.github.com>
Date: Wed, 14 Jan 2026 11:59:25 +0200
Subject: [PATCH 222/272] Add RotatedBinarySearch (search in rotated sorted
array) (#7202)
* feat: implement Smooth Sort algorithm with detailed JavaDoc and test class
* style: format LEONARDO array for improved readability with clang-format
* feat(sorts): add TournamentSort (winner-tree)
* test: add unit test for null array handling in TournamentSort
* feat(search): add rotated binary search
* test: add unit test for handling middle element in right sorted half of rotated array
---------
Co-authored-by: Ahmed Allam <60698204+AllamF5J@users.noreply.github.com>
---
.../searches/RotatedBinarySearch.java | 60 +++++++++++++++++++
.../searches/RotatedBinarySearchTest.java | 53 ++++++++++++++++
2 files changed, 113 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/searches/RotatedBinarySearch.java
create mode 100644 src/test/java/com/thealgorithms/searches/RotatedBinarySearchTest.java
diff --git a/src/main/java/com/thealgorithms/searches/RotatedBinarySearch.java b/src/main/java/com/thealgorithms/searches/RotatedBinarySearch.java
new file mode 100644
index 000000000000..86099b2fa2fa
--- /dev/null
+++ b/src/main/java/com/thealgorithms/searches/RotatedBinarySearch.java
@@ -0,0 +1,60 @@
+package com.thealgorithms.searches;
+
+import com.thealgorithms.devutils.searches.SearchAlgorithm;
+
+/**
+ * Searches for a key in a sorted array that has been rotated at an unknown pivot.
+ *
+ *
+ * Example:
+ * {@code [8, 9, 10, 1, 2, 3, 4, 5, 6, 7]}
+ *
+ *
+ * This is a modified binary search. When the array contains no duplicates, the
+ * time complexity is {@code O(log n)}. With duplicates, the algorithm still
+ * works but may degrade to {@code O(n)} in the worst case.
+ *
+ * @see Search in rotated sorted array
+ * @see SearchAlgorithm
+ */
+public final class RotatedBinarySearch implements SearchAlgorithm {
+
+ @Override
+ public > int find(T[] array, T key) {
+ int left = 0;
+ int right = array.length - 1;
+
+ while (left <= right) {
+ int middle = (left + right) >>> 1;
+ int cmp = key.compareTo(array[middle]);
+ if (cmp == 0) {
+ return middle;
+ }
+
+ // Handle duplicates: if we cannot determine which side is sorted.
+ if (array[left].compareTo(array[middle]) == 0 && array[middle].compareTo(array[right]) == 0) {
+ left++;
+ right--;
+ continue;
+ }
+
+ // Left half is sorted.
+ if (array[left].compareTo(array[middle]) <= 0) {
+ if (array[left].compareTo(key) <= 0 && key.compareTo(array[middle]) < 0) {
+ right = middle - 1;
+ } else {
+ left = middle + 1;
+ }
+ } else {
+ // Right half is sorted.
+ if (array[middle].compareTo(key) < 0 && key.compareTo(array[right]) <= 0) {
+ left = middle + 1;
+ } else {
+ right = middle - 1;
+ }
+ }
+ }
+
+ return -1;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/searches/RotatedBinarySearchTest.java b/src/test/java/com/thealgorithms/searches/RotatedBinarySearchTest.java
new file mode 100644
index 000000000000..1e6ab4c37fcc
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/RotatedBinarySearchTest.java
@@ -0,0 +1,53 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+class RotatedBinarySearchTest {
+
+ @Test
+ void shouldFindElementInRotatedArrayLeftSide() {
+ RotatedBinarySearch search = new RotatedBinarySearch();
+ Integer[] array = {8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7};
+ assertEquals(2, search.find(array, 10));
+ }
+
+ @Test
+ void shouldFindElementInRotatedArrayRightSide() {
+ RotatedBinarySearch search = new RotatedBinarySearch();
+ Integer[] array = {8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7};
+ assertEquals(6, search.find(array, 2));
+ }
+
+ @Test
+ void shouldFindElementInNotRotatedArray() {
+ RotatedBinarySearch search = new RotatedBinarySearch();
+ Integer[] array = {1, 2, 3, 4, 5, 6, 7};
+ assertEquals(4, search.find(array, 5));
+ }
+
+ @Test
+ void shouldReturnMinusOneWhenNotFound() {
+ RotatedBinarySearch search = new RotatedBinarySearch();
+ Integer[] array = {4, 5, 6, 7, 0, 1, 2};
+ assertEquals(-1, search.find(array, 3));
+ }
+
+ @Test
+ void shouldHandleWhenMiddleIsGreaterThanKeyInRightSortedHalf() {
+ RotatedBinarySearch search = new RotatedBinarySearch();
+ Integer[] array = {6, 7, 0, 1, 2, 3, 4, 5};
+ assertEquals(2, search.find(array, 0));
+ }
+
+ @Test
+ void shouldHandleDuplicates() {
+ RotatedBinarySearch search = new RotatedBinarySearch();
+ Integer[] array = {2, 2, 2, 3, 4, 2};
+ int index = search.find(array, 3);
+ assertTrue(index >= 0 && index < array.length);
+ assertEquals(3, array[index]);
+ }
+}
From babc762478f94491209999ed120538be6b863d80 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 15 Jan 2026 23:24:40 +0100
Subject: [PATCH 223/272] chore(deps-dev): bump
com.mebigfatguy.fb-contrib:fb-contrib from 7.7.2 to 7.7.3 (#7211)
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.2 to 7.7.3.
- [Commits](https://github.com/mebigfatguy/fb-contrib/compare/v7.7.2...v7.7.3)
---
updated-dependencies:
- dependency-name: com.mebigfatguy.fb-contrib:fb-contrib
dependency-version: 7.7.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 d3db730327d3..a685e334460c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -127,7 +127,7 @@
com.mebigfatguy.fb-contrib
fb-contrib
- 7.7.2
+ 7.7.3
com.h3xstream.findsecbugs
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 224/272] 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 225/272] 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 226/272] 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 227/272] 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 228/272] 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 229/272] 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 230/272] 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 231/272] 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 232/272] 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 233/272] 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 234/272] 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 235/272] 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 236/272] 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 237/272] 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 238/272] 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 239/272] 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 240/272] 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 241/272] 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 242/272] 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 243/272] 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 244/272] 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 245/272] 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 246/272] 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 247/272] 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 248/272] 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 249/272] 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 250/272] 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 251/272] 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 252/272] 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 253/272] 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 254/272] 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 255/272] 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 256/272] 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 257/272] 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 258/272] 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 259/272] 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 260/272] 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 261/272] 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 262/272] 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 263/272] 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 264/272] 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 265/272] 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 266/272] 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 267/272] 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 268/272] 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 269/272] 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 270/272] 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 271/272] 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 272/272] 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