Introduction

Imagine a cereal company puts one of n different prizes in every box, chosen uniformly at random. You buy box after box. How many boxes do you need to complete the collection?

This is the Coupon Collector's Problem, a classic from probability theory. It is not a hard problem to state, and the answer is known exactly: the expected number of draws is nH(n)n \cdot H(n), where H(n)=1+12+13++1nH(n) = 1 + \frac{1}{2} + \frac{1}{3} + \cdots + \frac{1}{n} is the harmonic number — which grows like nln(n)n \cdot \ln(n) for large nn.

The formula is beautiful, but the feeling behind it is what stays with you. The first few coupons arrive almost immediately. The last few feel like they take forever — because they do. When you already have n1n-1 distinct coupons, the chance that the next draw gives you the missing one is only 1n\frac{1}{n}. On average you need nn more draws just for that final piece.

That asymmetry — fast start, agonizing finish — is not just a quirk of collecting. It appears in hashing, networking, testing, and anywhere randomness is used to cover a set of possibilities.

Try It

Choose the set size n and press Collect all to run one simulation. The bar chart shows how many draws were needed for each new distinct coupon. Watch how the bars grow taller as the set fills up — each new coupon becomes rarer.

<div class="controls">
  <label>{{set_size}} <b id="nLabel">8</b>
    <input type="range" id="nSlider" min="4" max="20" value="8" />
  </label>
  <button id="runBtn" type="button">{{collect_all}}</button>
  <button id="resetBtn" type="button" class="ghost">{{reset}}</button>
</div>
<div class="summary" id="summary"></div>
<div class="chart-wrap">
  <canvas id="chart"></canvas>
</div>
<div class="formula" id="formula"></div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; padding: .5rem; }
.controls { display: flex; align-items: center; gap: .8rem; flex-wrap: wrap; margin-bottom: .6rem; }
label { font-size: .9rem; display: flex; align-items: center; gap: .4rem; }
input[type=range] { width: 120px; accent-color: #1d3557; }
button { font: 600 14px system-ui, sans-serif; padding: .4rem .85rem;
         border: 1px solid #1d3557; background: #1d3557; color: #fff;
         border-radius: 8px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
.summary { font-size: .95rem; font-weight: 600; min-height: 1.4em; margin-bottom: .4rem; }
.summary.ok { color: #0a7d33; }
.chart-wrap { width: 100%; overflow-x: auto; }
canvas { display: block; }
.formula { font-size: .85rem; color: #444; margin-top: .5rem; line-height: 1.5; }
.formula b { color: #1d3557; }
// Code not found

Notice the pattern: the first coupon always takes exactly 1 draw. The second takes on average nn1\frac{n}{n-1}. The kk-th new coupon takes on average nnk+1\frac{n}{n-k+1} draws. Add them all up and you get nH(n)n \cdot H(n) — the harmonic series in disguise. Press Collect all several times to see the randomness, then compare the actual total with the formula's prediction.

The Real Math

The derivation is a masterpiece of elementary probability.

  • Phase kk: once you hold k1k-1 distinct coupons, each draw independently hits the missing coupons with probability nk+1n\frac{n-k+1}{n}. The number of draws to get the kk-th new coupon follows a geometric distribution with success probability p=nk+1np = \frac{n-k+1}{n}, so its expected value is nnk+1\frac{n}{n-k+1}.
  • Total expectation: by linearity, the expected total draws is

k=1nnnk+1=n(1+12+13++1n)=nH(n).\sum_{k=1}^{n} \frac{n}{n-k+1} = n \left(1 + \frac{1}{2} + \frac{1}{3} + \cdots + \frac{1}{n}\right) = n \cdot H(n).

  • Asymptotic: H(n)ln(n)+γH(n) \approx \ln(n) + \gamma (where γ0.5772\gamma \approx 0.5772 is the Euler–Mascheroni constant), so the expected total is approximately nln(n)+γnn \cdot \ln(n) + \gamma \cdot n.
  • Concentration: the actual number of draws concentrates tightly around this mean. A Markov / union-bound argument shows that the probability of needing more than n(lnn+c)n(\ln n + c) draws falls as ece^{-c} — so exceeding the mean by even 10n10n extra draws is already very unlikely.
  • Status: fully solved. The exact formula nH(n)n \cdot H(n) has been known since at least the 18th century (attributed to de Moivre and later to various probabilists). There is no open question about the expected value — only richer variants (e.g., non-uniform distributions, partial collections) remain active research.

The result shows up in disguise everywhere: a randomized algorithm that samples random inputs until all cases are covered, a hash table filling all buckets, or a test suite hitting all code paths — each is a coupon collector in hiding.

Where It Matters

The coupon collector's bound governs any situation where random trials must hit every member of a finite set:

  • Hash tables and load balancing: when nn items are hashed uniformly into nn buckets, how many inserts before every bucket is occupied? The answer is nln(n)n \cdot \ln(n) — exactly the coupon collector. This drives the analysis of open-addressing hash tables and birthday-paradox collision estimates.
  • Randomized coverage testing: a test suite that picks random inputs needs about nln(n)n \cdot \ln(n) tests to hit all nn code paths at least once. This is the probabilistic basis for random fuzzing strategies.
  • Network broadcasting: gossip protocols spread a message to nn nodes by randomly forwarding it. The time until every node has heard it is O(nln(n))O(n \cdot \ln(n)) rounds — a coupon collector argument in each round.
  • DNA and genome shotgun sequencing: to cover an entire genome of length nn with random short reads, you need roughly nln(n)L\frac{n \cdot \ln(n)}{L} reads of length LL to ensure no region is missed. The coupon collector bound gave the first rigorous estimates in early sequencing projects.
  • Sticker albums and card games: every collector experiences the phenomenon directly — the last few cards in a Panini album or trading card set feel impossibly rare, and they are: the expected number of packs for the final sticker is nn packs all by itself.

Understanding why the last few take so long is not just trivia. It is the key insight behind why birthday attacks on hash functions are cheaper than expected, why random testing needs more runs than intuition suggests, and why complete coverage is always harder than partial coverage.

Conclusion

The Coupon Collector's Problem is one of the most elegant results in probability: a simple question about collecting prizes yields an exact formula involving the harmonic series, and that formula turns out to govern a surprising range of real phenomena.

The key insight is the asymmetry of rarity. Early draws are cheap — almost any new draw gives you something new. But as the set fills up, each remaining coupon becomes rarer, and the expected wait grows as nremaining\frac{n}{\text{remaining}}. Summing those waits produces the logarithmic factor that makes complete coverage so much harder than partial coverage.

Next time you find yourself buying one last pack, waiting for one last random event, or running one last test — remember that you are not unlucky. You have hit the fundamental cost of completeness, and the math says the last few will always feel like forever.

Share this article

Pick a channel — or use your device's native share sheet.

Comments

Loading comments...

https://www.kipuhub.com/en/article/coupon-collector/Content licensed under CC BY-NC 4.0.