Skip to content
Open
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
59 changes: 59 additions & 0 deletions src/main/java/com/thealgorithms/maths/BellNumbers.java
Original file line number Diff line number Diff line change
@@ -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.
*
* <p>
* This implementation uses the Bell Triangle (Aitken's array) method.
* Time Complexity: O(n^2)
* Space Complexity: O(n^2)
* </p>
*
* @author Chahat Sandhu, <a href="https://github.com/singhc7">singhc7</a>
* @see <a href="https://en.wikipedia.org/wiki/Bell_number">Bell Number (Wikipedia)</a>
*/
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];
}
}
53 changes: 53 additions & 0 deletions src/test/java/com/thealgorithms/maths/BellNumbersTest.java
Original file line number Diff line number Diff line change
@@ -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));
}
}