💻
Algorithm
  • README
  • Array
    • At Most To Equal
    • Count Inversions In An Array
    • Interleaving Placement
    • Kadane
    • Left To Right State Transition
    • Permutation
    • Quick Select
    • Sliding Window
    • Two Pointers
  • Binary Tree
    • Avl Tree
    • Binary Search Tree
    • Serialization And Deserialization
    • Traversal
  • Company
    • Facebook
  • Cpp
    • Array
    • Memset 3 F
    • Overflow
  • Data Structure
    • Binary Indexed Tree
    • Segment Tree And Binary Index Tree
    • Segment Tree
    • Stack
    • Trie
    • Union Find
  • Dynamic Programming
    • Knapsack
      • 0 1 Knapsack
      • Bounded Knapsack
      • Unbounded Knapsack
    • Bitmask Dp
    • Dp On Subsets
    • Dp On Tree
    • Dp With Sorting
    • Selective State Dp
    • Travelling Salesperson
  • Graph
    • Minimum Spanning Tree
      • Kruskal
      • Prim
    • Shortest Path
      • Bellman Ford
      • Dijkstra
      • Floyd Warshall
      • Johnson
      • Shortest Path Faster Algorithm
    • Bi Directional Breadth First Search
    • Bipartite
    • Breadth First Search
    • Component Coloring
    • Component Count
    • Depth First Search
    • Eulerian Path
    • Maximum Bipartite Matching
    • Tarjan
    • Topological Sort
    • Tree Diameter
    • Tree Ring Order Traversal
  • Greedy
    • Greedy Scheduling
    • Regret Greedy
  • Math
    • Catalan Number
    • Combinatorics
    • Factorial
    • Factorization
    • Fast Pow
    • Gcd
    • Geometry
    • Get Digits
    • Lcm
    • Median Minimizes Sum Of Absolute Deviations
    • Mode
    • Modular Multiplicative Inverse
    • Palindrome
    • Prime Number
    • Round Up
    • Sieve Of Eratosthenes
    • Stars And Bars
    • Sum Of Sequence
  • Miscellaneous
    • Bin Packing
    • Floyds Tortoise And Hare
    • Hungarian
    • Palindrome
  • Sort
    • Bubble Sort
    • Cycle Sort
    • Heap Sort
    • Merge Sort
    • Quick Sort
    • Sorting
  • Stl
    • Cpp Stl
    • Istringstream
    • Lower Bound Upper Bound
    • Priority Queue
  • String
    • Kmp
    • Manacher
    • Rabin Karp
    • String Processing
    • Z
  • Backtracking
  • Binary Answer
  • Binary Lifting
  • Binary Search
  • Bit Manipulation
  • Date
  • Difference Array
  • Discretization
  • Divide And Conquer
  • Gray Code
  • Great Problems For Practice
  • Interval Scheduling Maximization
  • Io Optimization
  • K Subset Partitioning
  • Line Sweep
  • Longest Common Subsequence
  • Longest Increasing Subsequence
  • Meet In The Middle
  • Minmax
  • Mono Deque
  • Monotonic Stack
  • Offline Query
  • P And Np
  • Prefix State Map
  • Prefix Sum
  • Random
  • Reservoir Sampling
  • Reverse Polish Notation
  • Sqrt Decomposition
Powered by GitBook
On this page
  • Counting Combinations
  • When n is small -- Iteration
  • When n is large -- Dynamic Programming
  • Sum of combinations
  • Problems
  • Generating Combinations
  • Problems

Was this helpful?

  1. Math

Combinatorics

Counting Combinations

Cnk=Ankk!=n!k!⋅(n−k)!=(n−k+1)⋅(n−k+2)⋯nk!C_n^k = \frac{A_n^k}{k!} = \frac{n!}{k! \cdot (n - k)!} = \frac{(n-k+1)\cdot(n-k+2)\cdots n}{k!}Cnk​=k!Ank​​=k!⋅(n−k)!n!​=k!(n−k+1)⋅(n−k+2)⋯n​

When n is small -- Iteration

We can use the following equation:

Cnk=(n−k+1)⋅(n−k+2)⋯nk!=n−k+11⋅n−k+22⋯nkC_n^k = \frac{(n-k+1)\cdot(n-k+2)\cdots n}{k!} = \frac{n-k+1}{1}\cdot\frac{n-k+2}{2}\cdots\frac{n}{k}Cnk​=k!(n−k+1)⋅(n−k+2)⋯n​=1n−k+1​⋅2n−k+2​⋯kn​

We compute from the smaller side $\frac{n-k+1}{1}$ to avoid the potential non-divisible error caused by $\frac{n}{k}$.

// Author: github.com/lzl124631x
// Time: O(min(K, N - K))
// Space: O(1)
int combination(int n, int k) {
    k = min(k, n - k); // Since we loop in range [1, k], we make sure `k` is smaller than `n - k`
    long ans = 1;
    for (int i = 1; i <= k; ++i) {
        ans = ans * (n - k + i) / i; // compute from the smaller side
    }
    return ans;
}

When n is large -- Dynamic Programming

To avoid overflow, we will be asked to return the answer modulo some prime number (1e9+7 on LeetCode).

We can't change the above solution to ans = ans * (n - k + i) / i % mod because after a previous modulo operation, ans * (n - k + i) might not be divisible by i.

We need to use this equation:

Cnk=Cn−1k−1+Cn−1kC_n^k = C_{n-1}^{k-1} + C_{n-1}^kCnk​=Cn−1k−1​+Cn−1k​

Memo: Picking k elements from n elements is the same as the sum of the following:

  1. Pick the first element, and pick k - 1 elements from the rest n - 1 elements, i.e. $C_{n-1}^{k-1}$

  2. Skip the first element, and pick k elements from the rest n - 1 elements, i.e. $C_{n-1}^k$

This can be computed using Pascal Triangle and Dynamic Programming.

  k  0  1  2  3  4
n  _______________
0 |  1  0  0  0  0
1 |  1  1  0  0  0
2 |  1  2  1  0  0
3 |  1  3  3  1  0
4 |  1  4  6  4  1
dp[i][j] = dp[i-1][j-1] + dp[i-1][j]
dp[i][0] = 1

And the answer is dp[n][k].

// Author: github.com/lzl124631x
// Time: O(NK)
// Space: O(K * (N - K))
int combination(int n, int k, int mod) {
    k = min(k, n - k);
    vector<vector<int>> dp(n + 1, vector<int>(k + 1));
    for (int i = 0; i <= n; ++i) dp[i][0] = 1;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= k; ++j) {
            dp[i][j] = (dp[i - 1][j - 1] + dp[i - 1][j]) % mod;
        }
    }
    return dp[n][k];
}

Since dp[i][j] only depends on dp[i-1][j-1] and dp[i-1][j], we can use 1D array to store the DP values. The answer is dp[k].

// Author: github.com/lzl124631x
// Time: O(NK)
// Space: O(min(K, N - K))
int combination(int n, int k, int mod) {
    k = min(k, n - k);
    vector<int> dp(k + 1);
    dp[0] = 1;
    for (int i = 1; i <= n; ++i) {
        for (int j = min(i, k); j > 0; --j) {
            dp[j] = (dp[j] + dp[j - 1]) % mod;
        }
    }
    return dp[k];
}

Sum of combinations

We can use the following equation to get some useful conclusions:

(a+b)n=Cn0⋅a0⋅bn+Cn1⋅a1⋅bn−1+⋯+Cnn⋅an⋅b0(a + b)^n = C_n^0\cdot a^0\cdot b^n + C_n^1\cdot a^1\cdot b^{n-1} + \dots + C_n^n\cdot a^n\cdot b^0(a+b)n=Cn0​⋅a0⋅bn+Cn1​⋅a1⋅bn−1+⋯+Cnn​⋅an⋅b0

Let a = 1, b = 1, we have

Cn0+Cn1+Cn2+⋯+Cnn−1+Cnn=2nC_n^0 + C_n^1 + C_n^2 + \dots + C_n^{n-1} + C_n^n = 2^nCn0​+Cn1​+Cn2​+⋯+Cnn−1​+Cnn​=2n

Let a = 1, b = -1, we have

Cn0−Cn1+Cn2−Cn3+Cn4−Cn5+⋯=0C_n^0 - C_n^1 + C_n^2 - C_n^3 + C_n^4 - C_n^5 + \dots = 0Cn0​−Cn1​+Cn2​−Cn3​+Cn4​−Cn5​+⋯=0

So

∑pCnp=∑qCnq=2n−1\sum_{p}C_n^p = \sum_{q}C_n^q = 2^{n-1}p∑​Cnp​=q∑​Cnq​=2n−1

where p and q represent all the even and odd numbers in [0, n], respectively.

Problems

Generating Combinations

Problems

PreviousCatalan NumberNextFactorial

Last updated 1 year ago

Was this helpful?

Try this in

Try this in

We can use this trick in

62. Unique Paths (Medium)
1569. Number of Ways to Reorder Array to Get Same BST (Hard)
1863. Sum of All Subset XOR Totals (Easy)
62. Unique Paths (Medium)
1569. Number of Ways to Reorder Array to Get Same BST (Hard)
1863. Sum of All Subset XOR Totals (Easy)
2400. Number of Ways to Reach a Position After Exactly k Steps (Medium)
2842. Count K-Subsequences of a String With Maximum Beauty (Hard)
77. Combinations (Medium)
1601. Maximum Number of Achievable Transfer Requests (Hard)