Problem
Given two parameters n and k and returns the value of Binomial Coefficient C(n, k).
Definition
Binomial coefficients, denoted by C(n, k), have two common interpretations:
- the coefficient of
X^k
in the expansion of(1 + X)^n
. For eg., in(1 + X)^3
,C(3, 2)
gives you the coefficient of the termX^2
. Expanding the expression, we see3X^2
, and indeed,C(3, 2)
is equal to3
. - the number of ways to choose k objects from a set of n, regardless of order.
Formula
$$ C(n, k) \text{ OR } \binom{n}{k} = \frac{n!}{k! * (n - k)!} $$
Examples
Example 1:
Input: n = 4, k = 2
Output: 6
Explanation: C(4, 2) = 4 C 2 = 4! / (2! * 2!) = 24 / 2*2 = 6
Example 2:
Input: n = 5 and k = 2
Output: 10
Explanation: C(5, 2) = 5 C 2 = 5!/(3!*2!) = 10
Solution
Method 1 - Recursion
Optimal Substructure - The value of C(n, k) can be recursively calculated using following standard formula for Binomial Coefficients.
C(n, k) = C(n-1, k-1) + C(n-1, k)
C(n, 0) = C(n, n) = 1
Code
Java
public int binomialCoefficient(int n, int k) {
if (k > n) {
return 0; // C(n, k) is 0 when k > n
} else if (k == 0 || k == n) {
return 1; // C(n, 0) = C(n, n) = 1
} else {
// Recursive case: C(n, k) = C(n-1, k-1) + C(n-1, k)
return binomialCoefficient(n - 1, k - 1) + binomialCoefficient(n - 1, k);
}
}
Complexity
- ⏰ Time complexity:
O(2^n)
- 🧺 Space complexity:
O(n)
Method 2 - Top Down DP
As, we can see there exists overlapping problems OR optimal substructure to the problem:
graph TD A(((5, 3))) --> B(((4, 2))) A --> C(((4, 3))) B --> D(((3, 1))) B --> E(((3, 2))) C --> D C --> E D --> F(((2, 0))) E --> F E --> G(((2, 1)))
Code
Java
public int binomialCoefficientTopDownDP(int n, int k) {
// Helper function to calculate using memoization
return helper(n, k, new int[n + 1][k + 1]);
}
private int helper(int n, int k, int[][] memo) {
// If base case (C(n, 0) or C(n, n)) return 1
if (k == 0 || k == n) {
return 1;
}
if (memo[n][k] != 0) {
return memo[n][k];
}
return memo[n][k] = helper(n - 1, k - 1, memo) + helper(n - 1, k, memo);
}
Complexity
- ⏰ Time complexity:
O(n*k)
- 🧺 Space complexity:
O(n*k)
Method 3 - Bottom up DP
Code
Java
public int binomialCoefficientDP(int n, int k) {
int[][] dp = new int[n + 1][k + 1];
// Initialize base cases (C(n, 0) and C(n, n))
for (int i = 0; i <= n; i++) {
dp[i][0] = 1; // C(n, 0) = 1 for all n
dp[i][i] = 1; // C(n, n) = 1 for all n
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= k && j <= i; j++) {
// Apply the formula: C(n, k) = C(n-1, k-1) + C(n-1, k)
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
}
}
return dp[n][k];
}
Complexity
- ⏰ Time complexity:
O(n*k)
- 🧺 Space complexity:
O(n*k)
Method 4 - Mathematics
We can take use of this identity to calculate binomial coefficent:
$$ \binom{n}{k} = \binom{n}{n - k} $$ Why this identity holds? We have seen that the binomial coefficient is: $$ \binom{n}{k} = \frac{n!}{k! * (n - k)!} $$
Then,
$$
\binom{n}{n - k} = \frac{n!}{(n - k)! * (n - (n - k))!} = \frac{n!}{(n - k)! * (k)!} = \binom{n}{k}
$$
Notice that after simplifying the latter, the factorial terms match with the former. In both expressions, (n-k)!
is the number of ways to arrange the not chosen elements, and k!
is the number of ways to arrange the chosen elements within the subsets. Since we aren’t interested in how the subsets themselves are ordered - only in their composition - both expressions simplify to the same thing.
Also, lets expand on C(n, k)
:
$$ \binom{n}{k} = \frac{n!}{k! * (n - k)!} = \frac{n * (n - 1) * … (n - k + 1) * (n - k)!}{k! * (n - k)!} $$ On simplifying we get:
$$ \binom{n}{k} = \frac{n * (n - 1) * … * (n - k + 1)}{ k! } = \frac{n * (n - 1) * … * (n - k + 1)}{k * (k - 1) * … *1} $$
Algorithm
- Change
k
ton - k
ifk > (n - k)
- Run loop
k
times from0 ... k - 1
say with iteratori
- Calculate each term as as
(ans * (n - i)) / (i + 1)
Code
Java
public int binomialCoefficient(int n, int k) {
// Since C(n, k) = C(n, n-k)
if (k > n - k) {
k = n - k;
}
int ans = 1;
for (int i = 0; i < k; ++i) {
ans *= (n - i);
ans /= (i + 1);
}
return ans;
}
Complexity
- ⏰ Time complexity:
O(k)
(as we loop from0
tok
) - 🧺 Space complexity:
O(1)