AnyLearn
All lessons
Mathintermediate

Counting Without Listing

Combinatorics answers how many arrangements exist without producing any of them, which is what makes password strength, hash collisions and search-space size computable at all. This lesson builds the product rule, permutations, combinations, inclusion-exclusion and the pigeonhole principle, then applies them to problems where intuition is reliably wrong.

Updated · AI-authored, review-gated · how lessons are made

Not signed in: your progress and quiz score won't be saved.
Progress1 / 10

The question behind a lot of engineering questions

How strong is an 8-character password? How many items before a hash function collides? How many test cases does exhaustive coverage need? How many ways can a scheduler order these jobs?

All four are the same question: how many things are in a set that is far too large to write down. Combinatorics answers it by counting structure rather than objects, which is why it produces an exact number for a set with more members than there are atoms nearby.

Key idea: Counting is not arithmetic on a list. It is decomposing a choice into independent stages, working out how many options each stage has, and combining those numbers with two rules. Almost everything else in this lesson is a special case of doing that carefully.

Full lesson text

All 10 steps on one page, for reading, reference, and search.

Show

1. The question behind a lot of engineering questions

How strong is an 8-character password? How many items before a hash function collides? How many test cases does exhaustive coverage need? How many ways can a scheduler order these jobs?

All four are the same question: how many things are in a set that is far too large to write down. Combinatorics answers it by counting structure rather than objects, which is why it produces an exact number for a set with more members than there are atoms nearby.

Key idea: Counting is not arithmetic on a list. It is decomposing a choice into independent stages, working out how many options each stage has, and combining those numbers with two rules. Almost everything else in this lesson is a special case of doing that carefully.

2. The two rules everything is built from

The product rule. If a task is a sequence of independent stages with n1,n2,,nkn_1, n_2, \dots, n_k options each, the number of outcomes is the product n1×n2××nkn_1 \times n_2 \times \cdots \times n_k. Stages that happen together multiply.

The sum rule. If a task is one of several mutually exclusive alternatives, the counts add. Choices that are alternatives to each other add.

An 8-character password over the 95 printable ASCII characters is eight independent stages of 95 options:

958=6,634,204,312,890,6256.6×101595^8 = 6{,}634{,}204{,}312{,}890{,}625 \approx 6.6 \times 10^{15}

That number sounds enormous and is not. At 101210^{12} guesses per second, a rate modern hardware reaches against a weak hash, the entire space falls in under two hours. Counting is what turns a vague feeling about security into a decision.

3. Order matters, or it does not

Almost every counting mistake is choosing the wrong one of these two.

P(n,k)=n!(nk)!C(n,k)=(nk)=n!k!(nk)!P(n, k) = \frac{n!}{(n-k)!} \qquad\qquad C(n, k) = \binom{n}{k} = \frac{n!}{k!\,(n-k)!}

Permutations P(n,k)P(n,k) count ordered selections: which three finish first, second and third. Combinations C(n,k)C(n,k) count unordered ones: which three made the team. The only difference is the k!k! in the denominator, dividing out the orderings of each chosen set, since order no longer distinguishes them.

Try it: A lottery draws 6 numbers from 49 and order is irrelevant. C(49,6)=13,983,816C(49,6) = 13{,}983{,}816, so a single ticket wins about once in fourteen million. If order mattered it would be P(49,6)P(49,6), which is 720 times larger, because 6!=7206! = 720 orderings collapse into each unordered draw.

4. Counting the same thing twice

The sum rule requires alternatives to be mutually exclusive. When they overlap, adding double-counts the overlap, and inclusion-exclusion is the correction:

AB=A+BAB|A \cup B| = |A| + |B| - |A \cap B|

ABC=A+B+CABACBC+ABC|A \cup B \cup C| = |A| + |B| + |C| - |A \cap B| - |A \cap C| - |B \cap C| + |A \cap B \cap C|

The alternating signs continue for more sets, adding odd-sized intersections and subtracting even-sized ones.

In practice: This is the same correction a query planner applies when estimating how many rows match several predicates, and the same one you need when reporting "users who did A or B" from two overlapping cohorts. Adding the two cohort sizes is the single most common reporting error in analytics, and it always overstates.

5. The most useful obvious statement in mathematics

If you put n+1n+1 items into nn boxes, some box holds at least two. Nobody disputes it, and it proves things that look much harder.

  • Lossless compression cannot shrink every input. There are fewer short strings than long ones, so no injective map from all nn-bit inputs into shorter outputs exists. Any compressor that shrinks some inputs must expand others.
  • Hash collisions are guaranteed, not merely likely. A hash maps an unbounded input space into a fixed number of outputs, so collisions exist by counting. Cryptographic strength is about being unable to find them, never about their absence.
  • Two people in London have the same number of hairs. A head holds fewer than a million hairs and the city holds millions of people.

Key idea: The pigeonhole principle proves existence without construction. It tells you a collision is there and offers no help at all in locating it, which is exactly the gap cryptography lives in.

6. How many people before two share a birthday?

Predict first

Ignoring leap years and assuming birthdays are uniform, how many people do you need in a room for a better-than-even chance that two share a birthday?

The calculation is easier backwards. Compute the probability that everyone differs, which is a clean product, then subtract from 1:

P(shared)=1365365364365365n+1365P(\text{shared}) = 1 - \frac{365}{365} \cdot \frac{364}{365} \cdots \frac{365 - n + 1}{365}

Counting the complement instead of the event is one of the most reliable moves in combinatorics, and it works here because "all distinct" is a product of independent-looking choices while "at least one match" is not.

7. The curve that surprises people

Probability that two people in a room share a birthday
percent (%)0204060801005102023305070
Source: Computed: 1 minus the product of (365-i)/365 for i from 0 to n-1

The shape is the point. It climbs slowly, then steeply through the middle, then flattens against 100 percent. By 50 people it is 97 percent and by 70 it is a near certainty, in a room holding a fifth of the number of days in a year.

The reason is that pairs, not people, are what collide, and nn people make (n2)\binom{n}{2} pairs, which grows quadratically. Doubling the room roughly quadruples the opportunities for a match.

8. The same arithmetic sizes your hash

Replace 365 with the size of a hash output space and the birthday calculation becomes a security parameter. A collision becomes likely after roughly N\sqrt{N} items, not NN, so an nn-bit hash gives you about n/2n/2 bits of collision resistance.

Hash widthDistinct outputsItems for a 50% collision chance
32-bit4.3×1094.3 \times 10^9about 77,000
64-bit1.8×10191.8 \times 10^{19}about 5.1×1095.1 \times 10^9
128-bit3.4×10383.4 \times 10^{38}about 2.2×10192.2 \times 10^{19}
256-bit1.2×10771.2 \times 10^{77}about 4.0×10384.0 \times 10^{38}

Gotcha: A 32-bit hash sounds like four billion possibilities and collides after about seventy-seven thousand entries. That is a medium-sized table, not an astronomical one, and it is why 32-bit checksums are fine for detecting accidental corruption and useless as identifiers.

9. Counting in code, and where it goes wrong

Python's standard library has the exact functions, and using them beats hand-rolled factorials that overflow or lose precision.

import math
from itertools import combinations, permutations

math.comb(49, 6)          # 13983816   unordered
math.perm(49, 6)          # 10068347520 ordered
math.factorial(20)        # exact, arbitrary precision

# enumerate only when the count is small enough to justify it
len(list(combinations(range(49), 6)))   # same 13983816, minutes and gigabytes

Gotcha: The habit of checking a count by enumerating stops working almost immediately. combinations over 49 items taken 6 at a time is already fourteen million tuples. Verify small cases by enumeration, then trust the formula: that pattern, small case by brute force and general case by argument, is what the next lesson formalises as proof by induction.

10. A procedure for counting problems

Most counting errors are not arithmetic. They are misreading the structure of the choice, and a fixed procedure catches nearly all of them.

  1. Describe one outcome precisely. If you cannot say exactly what a single element of the set looks like, you are not ready to count them.
  2. Ask whether order distinguishes outcomes. Permutation if yes, combination if no. Ask it explicitly rather than assuming.
  3. Ask whether repetition is allowed. Passwords repeat characters; lottery draws do not, and the formulas differ.
  4. Decompose into stages, and check independence. The product rule needs each stage's option count to be the same whatever the earlier stages chose.
  5. Check for overlap and for double counting. If two different stage sequences produce the same outcome, divide; if alternatives overlap, use inclusion-exclusion.
  6. Sanity-check on a tiny case. Set n=3n = 3 and count by hand. A formula that fails at 3 fails everywhere.

Check your understanding

The lesson ends with a 5-question quiz. Take it in the player above to see your score.

  1. A team of 4 is chosen from 12 candidates, with no roles assigned. How many possible teams?
    • C(12,4) = 495
    • P(12,4) = 11880
    • 12^4 = 20736
    • 4! = 24
  2. Why does a 64-bit hash reach a 50% chance of collision after only about 5 billion items rather than 9 quintillion?
    • Because real hash functions are not uniform
    • Because collisions become likely near the square root of the output space, since pairs collide and pairs grow quadratically
    • Because 64-bit hashes reserve half their bits for structure
    • Because the pigeonhole principle guarantees a collision at that point
  3. Two cohorts, A with 5,000 users and B with 3,000, overlap in 1,200 users. How many did A or B?
    • 8,000
    • 9,200
    • 6,800
    • 3,800
  4. What does the pigeonhole principle establish about a lossless compressor?
    • That it can shrink any input given enough passes
    • That its compression ratio is bounded by the entropy of the source
    • That collisions in its dictionary are unavoidable
    • That if it shrinks some inputs, it must expand others
  5. Why is the birthday probability computed via 'nobody shares' rather than directly?
    • Because the complement is a clean product of independent-looking choices, while 'at least one match' is not
    • Because the direct calculation gives a different answer
    • Because the direct sum diverges for n above 365
    • Because probabilities of unions are always easier than intersections

Related lessons

Math
intermediate

Modular Arithmetic: Doing Maths on a Clock

Wrap the number line into a circle and addition and multiplication survive intact while division mostly does not. This lesson builds congruences, shows why you can reduce early to avoid overflow, works through Euclid's algorithm and modular inverses, and explains how a million-digit exponent becomes twenty multiplications.

10 steps·~15 min
Math
intermediate

Graphs: A Language for Relationships

A graph is two sets and an incidence relation, and that austerity is why the same object models build dependencies, social networks, register allocation and road maps. This lesson covers the structural properties worth knowing, the special families that make hard problems easy, and the line where a small change to a question makes it intractable.

10 steps·~15 min
Math
intermediate

Proof and Induction: Covering Infinitely Many Cases

Testing checks the cases you thought of; a proof covers all of them at once, including the ones nobody will ever run. This lesson builds direct proof, contradiction and induction as working tools, shows the two ways induction fails, and connects it to the loop invariants that make a program correct rather than merely untested.

10 steps·~15 min
Computer Science
advanced

Bloom Filters: Membership in a Bit Array

A Bloom filter answers set membership using a bit array and a handful of hash functions, with no items stored anywhere. This lesson builds it, derives the sizing formula that trades memory against false positives, explains exactly why deletion is impossible, and covers the variants that buy it back.

8 steps·~12 min