Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions src/main/java/com/thealgorithms/maths/CatalanNumbers.java
Original file line number Diff line number Diff line change
@@ -1,38 +1,43 @@
package com.thealgorithms.maths;

import java.math.BigInteger;

/**
* Calculate Catalan Numbers
*/
public final class CatalanNumbers {
private static final int MAX_SUPPORTED_INDEX = 35;

private CatalanNumbers() {
}

/**
* Calculate the nth Catalan number using a recursive formula.
* Calculate the nth Catalan number using the factorial formula.
*
* @param n the index of the Catalan number to compute
* @return the nth Catalan number
* @throws IllegalArgumentException if n is negative or exceeds the maximum supported index for long
*/
public static long catalan(final int n) {
if (n < 0) {
throw new IllegalArgumentException("Index must be non-negative");
}
return factorial(2 * n) / (factorial(n + 1) * factorial(n));
if (n > MAX_SUPPORTED_INDEX) {
throw new IllegalArgumentException("Index exceeds maximum supported value for long");
}
return factorial(2 * n).divide(factorial(n + 1).multiply(factorial(n))).longValueExact();
}

/**
* Calculate the factorial of a number.
* Calculate the factorial of a number using BigInteger to prevent integer overflow.
*
* @param n the number to compute the factorial for
* @return the factorial of n
* @return the factorial of n as BigInteger
*/
private static long factorial(final int n) {
if (n == 0 || n == 1) {
return 1;
}
long result = 1;
private static BigInteger factorial(final int n) {
BigInteger result = BigInteger.ONE;
for (int i = 2; i <= n; i++) {
result *= i;
result = result.multiply(BigInteger.valueOf(i));
}
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class CatalanNumbersTest {
* [input number, expected Catalan number for that input]
*/
static Stream<Object[]> catalanNumbersProvider() {
return Stream.of(new Object[] {0, 1}, new Object[] {1, 1}, new Object[] {2, 2}, new Object[] {3, 5}, new Object[] {4, 14}, new Object[] {5, 42}, new Object[] {6, 132}, new Object[] {7, 429}, new Object[] {8, 1430}, new Object[] {9, 4862}, new Object[] {10, 16796});
return Stream.of(new Object[] {0, 1L}, new Object[] {1, 1L}, new Object[] {2, 2L}, new Object[] {3, 5L}, new Object[] {4, 14L}, new Object[] {5, 42L}, new Object[] {6, 132L}, new Object[] {7, 429L}, new Object[] {8, 1430L}, new Object[] {9, 4862L}, new Object[] {10, 16796L},
new Object[] {11, 58786L}, new Object[] {15, 9694845L}, new Object[] {35, 3116285494907301262L});
}

/**
Expand All @@ -28,7 +29,7 @@ static Stream<Object[]> catalanNumbersProvider() {
*/
@ParameterizedTest
@MethodSource("catalanNumbersProvider")
void testCatalanNumbers(int input, int expected) {
void testCatalanNumbers(int input, long expected) {
assertEquals(expected, CatalanNumbers.catalan(input), () -> String.format("Catalan number for input %d should be %d", input, expected));
}

Expand All @@ -39,5 +40,6 @@ void testCatalanNumbers(int input, int expected) {
void testIllegalInput() {
assertThrows(IllegalArgumentException.class, () -> CatalanNumbers.catalan(-1));
assertThrows(IllegalArgumentException.class, () -> CatalanNumbers.catalan(-5));
assertThrows(IllegalArgumentException.class, () -> CatalanNumbers.catalan(36));
}
}
Loading