Given an integer n representing a set of n distinct elements, find the number of ways to partition the set into one or more non-empty subsets.
- The order of subsets does not matter, and every element must belong to exactly one subset.
- Since the answer can be very large, return it modulo 10^9+7.
Examples:
Input: n = 2
Output: 2
Explanation: Let the set be {1, 2}, the possible partitions are: {{1}, {2}} and {{1, 2}}. Hence, the answer is 2.Input: n = 3
Output: 5
Explanation: Let the set be {1, 2, 3}, there are 5 distinct ways to partition the elements into one or more non-empty subsets. Hence, the answer is 5.
Table of Content
[Naive Approach] Using Recursion on Stirling Numbers – O(2^n) Time and O(n) Space
A Bell Number counts the total number of ways to partition a set of n elements into any number of non-empty subsets.
Let S(n, k) represents the number of ways to partition n elements into exactly k non-empty subsets. The Bell Number is simply the sum of S(n, k) over all k from 1 to n. The number S(n, k) is called Sterling Number
How do we make k subsets?
To place the nth element, we have two choices:
- Drop it into one of the existing subsets. We recursively call for n-1 and k.
- Start a brand new subset of its own. We recursively call for n-1 and k - 1.
Trying both choices for every element and recursing down to the base case gives us the count.
#include <bits/stdc++.h>
using namespace std;
int stirling(int n, int k) {
if (n == 0 && k == 0) return 1;
if (n == 0 || k == 0) return 0;
if (k > n) return 0;
if (k == 1 || k == n) return 1;
// Either nth element joins existing subset or forms new one
return k * stirling(n - 1, k) + stirling(n - 1, k - 1);
}
int bellNumber(int n) {
int res = 0;
// Sum Stirling numbers for all possible subset counts
for (int k = 1; k <= n; k++)
res += stirling(n, k);
return res;
}
int main() {
int n = 2;
cout << bellNumber(n) << endl;
return 0;
}
class GfG {
static int stirling(int n, int k) {
if (n == 0 && k == 0) return 1;
if (n == 0 || k == 0) return 0;
if (k > n) return 0;
if (k == 1 || k == n) return 1;
// Either nth element joins existing subset or forms new one
return k * stirling(n - 1, k) + stirling(n - 1, k - 1);
}
static int bellNumber(int n) {
int res = 0;
// Sum Stirling numbers for all possible subset counts
for (int k = 1; k <= n; k++)
res += stirling(n, k);
return res;
}
public static void main(String[] args) {
int n = 2;
System.out.println(bellNumber(n));
}
}
def stirling(n, k):
if n == 0 and k == 0:
return 1
if n == 0 or k == 0:
return 0
if k > n:
return 0
if k == 1 or k == n:
return 1
# Either nth element joins existing subset or forms new one
return k * stirling(n - 1, k) + stirling(n - 1, k - 1)
def bellNumber(n):
res = 0
# Sum Stirling numbers for all possible subset counts
for k in range(1, n + 1):
res += stirling(n, k)
return res
if __name__ == "__main__":
n = 2
print(bellNumber(n))
using System;
class GfG {
static int stirling(int n, int k) {
if (n == 0 && k == 0) return 1;
if (n == 0 || k == 0) return 0;
if (k > n) return 0;
if (k == 1 || k == n) return 1;
// Either nth element joins existing subset or forms new one
return k * stirling(n - 1, k) + stirling(n - 1, k - 1);
}
static int bellNumber(int n) {
int res = 0;
// Sum Stirling numbers for all possible subset counts
for (int k = 1; k <= n; k++)
res += stirling(n, k);
return res;
}
static void Main() {
int n = 2;
Console.WriteLine(bellNumber(n));
}
}
function stirling(n, k) {
if (n === 0 && k === 0) return 1;
if (n === 0 || k === 0) return 0;
if (k > n) return 0;
if (k === 1 || k === n) return 1;
// Either nth element joins existing subset or forms new one
return k * stirling(n - 1, k) + stirling(n - 1, k - 1);
}
function bellNumber(n) {
let res = 0;
// Sum Stirling numbers for all possible subset counts
for (let k = 1; k <= n; k++)
res += stirling(n, k);
return res;
}
// Driver code
const n = 2;
console.log(bellNumber(n));
Output
2
[Expected Approach] Using Bell Triangle with Space Optimization – O(n^2) Time and O(n) Space
A simple way to optimize the above approach is to use Dynamic Programming by storing solutions of subproblems. We create a 2D dp[][] array of size (n+1)*(n+1) and compute results as dp[i][j] = j * dp[i - 1][j] + dp[i - 1][j - 1]. If we observe carefully, we can notice that the current row is dependent on the previous row.
A Bell Triangle is like Pascal's Triangle - each row is built only from the row directly above it. So instead of storing the whole triangle, we just keep the previous row, build the current row from it, and discard the old one. The first number of row n is our answer.
Below is a sample Bell Triangle for first few Bell Numbers.
1
1 2
2 3 5
5 7 10 15
15 20 27 37 52
Step By Step Implementation:
- Start with prev = [1], representing row 0 of the Bell Triangle.
- For row i from 1 to n, create a new row curr of size i+1.
- Set curr[0] to the last element of prev — this carries the row over.
- Fill the rest: curr[j] = prev[j-1] + curr[j-1], taking the diagonal-left and left neighbor.
- After building row n, discard prev and return curr[0] (now stored back in prev) as the Bell Number.
#include <bits/stdc++.h>
using namespace std;
int bellNumber(int n) {
const int MOD = 1e9 + 7;
// Rolling array - only store previous row instead of full triangle
vector<long long> prev = {1};
for (int i = 1; i <= n; i++) {
vector<long long> curr(i + 1, 0);
// First element of current row comes from
// the last element of previous row.
curr[0] = prev[prev.size() - 1];
for (int j = 1; j <= i; j++) {
// Build Bell Triangle using the cell
// above-left and the previous cell.
curr[j] = (prev[j - 1] + curr[j - 1]) % MOD;
}
prev = curr;
}
return prev[0];
}
int main() {
int n = 2;
cout << bellNumber(n) << endl;
return 0;
}
class GfG {
static int bellNumber(int n) {
int MOD = 1_000_000_007;
// Rolling array - only store previous row instead of full triangle
long[] prev = {1};
for (int i = 1; i <= n; i++) {
long[] curr = new long[i + 1];
// First element of current row comes from
// the last element of previous row.
curr[0] = prev[prev.length - 1];
for (int j = 1; j <= i; j++) {
// Build Bell Triangle using the cell
// above-left and the previous cell.
curr[j] = (prev[j - 1] + curr[j - 1]) % MOD;
}
prev = curr;
}
return (int) prev[0];
}
public static void main(String[] args) {
int n = 2;
System.out.println(bellNumber(n));
}
}
def bellNumber(n):
MOD = 1_000_000_007
# Rolling array - only store previous row instead of full triangle
prev = [1]
for i in range(1, n + 1):
curr = [0] * (i + 1)
# First element of current row comes from
# the last element of previous row.
curr[0] = prev[-1]
for j in range(1, i + 1):
# Build Bell Triangle using the cell
# above-left and the previous cell.
curr[j] = (prev[j - 1] + curr[j - 1]) % MOD
prev = curr
return prev[0]
if __name__ == "__main__":
n = 2
print(bellNumber(n))
using System;
class GfG {
static int bellNumber(int n) {
int MOD = 1_000_000_007;
// Rolling array - only store previous row instead of full triangle
long[] prev = {1};
for (int i = 1; i <= n; i++) {
long[] curr = new long[i + 1];
// First element of current row comes from
// the last element of previous row.
curr[0] = prev[prev.Length - 1];
for (int j = 1; j <= i; j++) {
// Build Bell Triangle using the cell
// above-left and the previous cell.
curr[j] = (prev[j - 1] + curr[j - 1]) % MOD;
}
prev = curr;
}
return (int) prev[0];
}
static void Main() {
int n = 2;
Console.WriteLine(bellNumber(n));
}
}
function bellNumber(n) {
const MOD = 1_000_000_007;
// Rolling array - only store previous row instead of full triangle
let prev = [1];
for (let i = 1; i <= n; i++) {
const curr = new Array(i + 1).fill(0);
// First element of current row comes from
// the last element of previous row.
curr[0] = prev[prev.length - 1];
for (let j = 1; j <= i; j++) {
// Build Bell Triangle using the cell
// above-left and the previous cell.
curr[j] = (prev[j - 1] + curr[j - 1]) % MOD;
}
prev = curr;
}
return prev[0];
}
// Driver code
const n = 2;
console.log(bellNumber(n));
Output
2