diff --git a/src/main/java/com/thealgorithms/divideandconquer/Factorial.java b/src/main/java/com/thealgorithms/divideandconquer/Factorial.java new file mode 100644 index 000000000000..ec9db6f2ff5d --- /dev/null +++ b/src/main/java/com/thealgorithms/divideandconquer/Factorial.java @@ -0,0 +1,39 @@ +package com.thealgorithms.divideandconquer; + +/** + * Computes the factorial of a non-negative integer using an iterative + * approach to avoid recursion overhead and stack overflow risks. + * + *
This implementation improves upon the original recursive version by + * eliminating deep recursion, reducing space complexity from O(n) to O(1), + * and improving runtime efficiency on the JVM. + * + *
Time Complexity: O(n)
+ *
Space Complexity: O(1)
+ */
+public final class Factorial {
+
+ private Factorial() {
+ // Utility class
+ }
+
+ /**
+ * Returns the factorial of the given non-negative number.
+ *
+ * @param n the number to compute factorial for
+ * @return factorial of n (n!)
+ * @throws IllegalArgumentException if n is negative
+ */
+ public static long factorial(long n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("Negative input not allowed");
+ }
+
+ long result = 1;
+ for (long i = 2; i <= n; i++) {
+ result *= i;
+ }
+
+ return result;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/maths/Factorial.java b/src/main/java/com/thealgorithms/maths/Factorial.java
deleted file mode 100644
index 511cc1f84f05..000000000000
--- a/src/main/java/com/thealgorithms/maths/Factorial.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.thealgorithms.maths;
-
-public final class Factorial {
- private Factorial() {
- }
-
- /**
- * Calculate factorial N using iteration
- *
- * @param n the number
- * @return the factorial of {@code n}
- */
- public static long factorial(int n) {
- if (n < 0) {
- throw new IllegalArgumentException("Input number cannot be negative");
- }
- long factorial = 1;
- for (int i = 1; i <= n; ++i) {
- factorial *= i;
- }
- return factorial;
- }
-}
diff --git a/src/main/java/com/thealgorithms/maths/FactorialRecursion.java b/src/main/java/com/thealgorithms/maths/FactorialRecursion.java
deleted file mode 100644
index d9bafd1e39e9..000000000000
--- a/src/main/java/com/thealgorithms/maths/FactorialRecursion.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.thealgorithms.maths;
-
-public final class FactorialRecursion {
- private FactorialRecursion() {
- }
- /**
- * Recursive FactorialRecursion Method
- *
- * @param n The number to factorial
- * @return The factorial of the number
- */
- public static long factorial(int n) {
- if (n < 0) {
- throw new IllegalArgumentException("number is negative");
- }
- return n == 0 || n == 1 ? 1 : n * factorial(n - 1);
- }
-}
diff --git a/src/test/java/com/thealgorithms/divideandconquer/FactorialTest.java b/src/test/java/com/thealgorithms/divideandconquer/FactorialTest.java
new file mode 100644
index 000000000000..50d63c5e970b
--- /dev/null
+++ b/src/test/java/com/thealgorithms/divideandconquer/FactorialTest.java
@@ -0,0 +1,82 @@
+package com.thealgorithms.divideandconquer;
+
+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;
+
+public class FactorialTest {
+ // --------------------------------------------------------
+ // SECTION 1: Basic Correctness Tests
+ // --------------------------------------------------------
+
+ @Test
+ void testFactorialOfFive() {
+ assertEquals(120, Factorial.factorial(5));
+ }
+
+ @Test
+ void testFactorialOfZero() {
+ assertEquals(1, Factorial.factorial(0));
+ }
+
+ @Test
+ void testNegativeInputThrowsException() {
+ assertThrows(IllegalArgumentException.class, () -> { Factorial.factorial(-5); });
+ }
+
+ // --------------------------------------------------------
+ // SECTION 2: Analysis-Oriented Test (Performance Awareness)
+ // --------------------------------------------------------
+
+ @Test
+ void testLargeInputPerformance() {
+ long start = System.currentTimeMillis();
+ long result = Factorial.factorial(15);
+ long end = System.currentTimeMillis();
+
+ assertEquals(1307674368000L, result);
+ assertTrue((end - start) < 50, "Factorial(15) took too long to compute");
+ }
+
+ // --------------------------------------------------------
+ // SECTION 3: Algorithmic Improvement Demonstration
+ // --------------------------------------------------------
+
+ /**
+ * Local copy of the original recursive implementation
+ * used only for comparing performance inside the test.
+ */
+ private long recursiveFactorial(long n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("Negative input not allowed");
+ }
+ if (n == 0 || n == 1) {
+ return 1;
+ }
+ return n * recursiveFactorial(n - 1);
+ }
+
+ @Test
+ void testIterativeFasterThanRecursive() {
+ long n = 18;
+
+ long startRec = System.nanoTime();
+ long recResult = recursiveFactorial(n);
+ long endRec = System.nanoTime();
+
+ long startIter = System.nanoTime();
+ long iterResult = Factorial.factorial(n);
+ long endIter = System.nanoTime();
+
+ assertEquals(recResult, iterResult);
+ assertTrue(endIter - startIter < endRec - startRec, "Iterative version should outperform recursive version");
+ }
+
+ @Test
+ void testIterativeHandlesLargerInputsSafely() {
+ assertDoesNotThrow(() -> Factorial.factorial(20));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/maths/FactorialRecursionTest.java b/src/test/java/com/thealgorithms/maths/FactorialRecursionTest.java
deleted file mode 100644
index db18b46356b4..000000000000
--- a/src/test/java/com/thealgorithms/maths/FactorialRecursionTest.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.thealgorithms.maths;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-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 FactorialRecursionTest {
- @ParameterizedTest
- @MethodSource("inputStream")
- void testFactorialRecursion(long expected, int number) {
- assertEquals(expected, FactorialRecursion.factorial(number));
- }
-
- private static Stream