Skip to content

Discrete Math and Proof

Counting and combinatorics

How many ways: permutations and combinations

A café offers 5 breads, 4 fillings, and 3 sauces. How many sandwiches are possible? You could write them all out - or you could multiply: . Combinatorics is the discipline of finding the size of a set without ever building the set. It is where probability finds its denominators, and where algorithms meet their worst case: the very same and that look tidy on paper are exactly what make brute force impossible in practice.

The one-line idea

Counting is multiplication and addition in disguise. Whenever something is built by a sequence of independent choices, the option counts multiply. Whenever it falls into one of several mutually exclusive cases, the counts add. Almost every formula in this lesson is those two rules applied until the pattern earns a name.

Two rules that generate everything

The rule of product. If a task is a sequence of independent stages, and stage can be done in ways regardless of the earlier choices, then the number of ways to do the whole task is the product:

The sandwich is three independent stages, so . A 4-character password over a 26-letter alphabet is . The key word is independent: choosing the bread must not shrink your filling options, or the clean product breaks.

The rule of sum. If the possibilities split into cases that never overlap, you add the cases. With and disjoint, . A committee that is "a math major or a physics major" (no double majors) has candidates. Product builds one thing from many parts; sum picks one option among alternatives.

Order matters, or it doesn't

Everything specializes from one question: when you pick items, does their order count as different?

Start with arranging all distinct items in a row. The first slot has choices, the next , and so on down to - the rule of product gives the factorial:

Now pick only of the and keep them in order. You stop the product after factors, which is a permutation:

If order does not matter - a set, not a sequence - then every group of items has been counted times, once per ordering. Divide it out to get the combination, read " choose ":

That last equation is the whole relationship: arranging = choosing, then ordering. The machine below makes it physical. Pick and , toggle whether order matters, and press Count: it reveals every valid output one at a time, and the running tally lands exactly on the formula.

Choose-vs-arrange machine. Toggle order, then press Count.
pool of n =ABCD
Unordered - selectionsC(4, 2)
C(4, 2) = 4!2! (4−2)!=242 · 2= 6
each set has 2! = 2 orderings → ordered would be 6 × 2 = 12

counted 6 of 6 outputs

ABACADBCBDCD

Each tile is one valid output. Unordered lists every distinct set; Ordered expands each set into all k! of its orderings - one group per row. Watch the ordered count be exactly k! times the unordered one.

The aha: ordering is a multiplier of exactly k!

Toggle between the two modes with and the grid stops hiding it: 6 unordered selections, 12 ordered arrangements - every set of two split into its orderings. That is why is with the divided back out. Combinations are permutations that forgot their order. Once you see the factor, you never again confuse "how many teams" (a combination) with "how many finishing orders" (a permutation).

The same three counts, in code

from math import factorial, comb, perm
from itertools import permutations, combinations

n, k = 5, 2
perm(n, k)      # 20  -> ordered:   n! / (n-k)!
comb(n, k)      # 10  -> unordered: n! / (k!(n-k)!)
comb(n, k) * factorial(k) == perm(n, k)   # True  -> P = C * k!

list(combinations("ABCDE", 2))   # 10 sets:  AB AC AD ... DE
list(permutations("ABCDE", 2))   # 20 ordered pairs: AB BA AC CA ...
The same three counts, in code

Pascal's triangle and the binomial theorem

The combinations obey one beautiful recurrence. To pick items from , fix your eye on the last item: either you take it (now pick from the remaining ) or you leave it (pick all from the other ). Those two cases are disjoint, so by the rule of sum:

Stack the in a pyramid and that identity says every number is the sum of the two directly above it. That is Pascal's triangle. Click any cell below to see the two parents that add up to it - and read off, at the edge of each row, that it always begins and ends with .

Pascal's triangle. Click a number to see its two parents.
111121133114641151010511615201561172135352171

Click any number. Each interior one is the sum of the two above it - that is the identity C(n,k) = C(n−1,k−1) + C(n−1,k).

Row of the triangle is more than pretty. Those numbers are exactly the coefficients when you expand a binomial to the -th power - the binomial theorem:

Why? Expanding means picking either or from each of the factors; the term appears once for every way to choose which factors donate a - and that count is . So , reading row 4: .

One row, and the number of subsets

Set in the binomial theorem and the left side becomes while the right becomes the sum of a whole row:
This is a counting identity you can read two ways. A set of elements has subsets - each element is independently in or out, the rule of product on two-way choices. Grouping those subsets by how many elements they contain gives . Both count the same subsets, so they must be equal. Every row of Pascal's triangle sums to a power of two.

Pigeonhole, and why brute force hits a wall

One last principle, almost insultingly simple yet startlingly powerful. The pigeonhole principle: if you place items into boxes and , then some box holds at least two items. More sharply, some box holds at least of them. It sounds trivial, but it proves that any two of the 8+ million people in New York share a birthday-count pattern, that any lossless compressor must expand some inputs, and that a hash table with more keys than buckets must collide.

Combinatorics is also the bearer of bad news. The counts we built don't just grow - they explode. Arranging things is ways; considering every subset is . At that is already permutations. This is the exact reason brute force is a trap, and the reason whole fields of algorithms exist to avoid enumerating what combinatorics counts.

Growth you cannot outrun with hardware

and outpace every polynomial and shrug off faster chips. Doubling your computer's speed lets a search handle exactly one more item; an search, often less than that. That is why "just try all of them" fails past small , and why the interesting question is never "can we enumerate?" but "can we avoid enumerating?" - the driving question of the next several lessons.

Check yourself

You line up 3 of 5 books on a shelf; swapping two books makes a different lineup. This is counted by:

How many 2-person teams can be formed from 5 people, where order within a team does not matter?

State n!, P(n,k), and C(n,k) - and how the two selection counts relate.

Try to state it, then check.

Lock it in

  • Counting is multiplication and addition in disguise: a sequence of independent choices multiplies (rule of product), mutually exclusive cases add (rule of sum).
  • Arranging all items is ; ordered picks are ; unordered picks are , related by .
  • Pascal's recurrence builds the triangle, whose row holds the binomial coefficients and sums to - the number of subsets of an -element set.
  • The pigeonhole principle: put items in boxes with and some box holds at least of them.
  • and outgrow every polynomial and shrug off faster hardware - the exact reason brute force is a trap. Reach for combinations when order is ignored, permutations when it counts.

Primary source

For the rigorous version - proofs, bijective counting, and the sum/product rules built from set theory - work through the counting unit of MIT's 6.042J Mathematics for Computer Science (Fall 2010), the canonical discrete-math course for programmers. For intuition-first practice with permutations and combinations, drill Khan Academy's Counting, permutations, and combinations unit.

Ask your teacher

Combinatorics is precisely why brute force explodes. Trying every ordering of items is work - the wall that backtracking (Lesson 44) spends its whole life pruning - and trying every subset is , the combinatorial heart of why P vs NP (Lesson 101) is hard: a verifier checks one certificate in polynomial time, yet a blind search may face of them. The same counts run straight through machine learning (Lesson 60), where a probability is a favorable-count divided by a total-count - and those counts are the binomials you just built. Ask me why eventually dwarfs , how Stirling's approximation tames , or how counting subsets connects to entropy and information.