HyperLogLog Cardinality Estimator
Count how many <i>distinct</i> items a stream contained — billions of them — using a few kilobytes, not a giant set. HyperLogLog turns "the longest run of leading zeros I saw" into a cardinality estimate. It powers COUNT(DISTINCT) in Redis, Presto and BigQuery. A provided hash keeps Python and TypeScript in sync. Hidden tests.
The problem
Implement hll_estimate(items, p): estimate the number of distinct values in items using HyperLogLog with 2^p registers. For each item, hash it (use the provided hash32); the top p bits pick a register, and the register keeps the maximum "rank" seen — the position of the leftmost 1-bit in the remaining bits (leading-zeros + 1). Combine the registers with the HLL formula and return the estimated cardinality as an integer.
hll_estimate(['a','b','c',...] (1000 distinct), p = 8)≈ 1000- Use the provided
hash32. There arem = 2^pregisters, all starting at 0. - Rank = leading-zeros-plus-one of the non-bucket bits: if the leftmost bits are 0, the rank is higher (rare, so a high rank hints at many distinct items).
- Estimate
E = alpha · m² / Σ 2^(−register). Apply the small-range correction: ifE ≤ 2.5mand some registers are still 0 (count V), useE = m · ln(m / V). Returnint(E). - It is an estimate — expected error is a few percent, not exact. That is the trade for tiny memory.
Your turn — write it
Edit the stub, hit Run (or ⌘/Ctrl + Enter), and watch the hidden tests. Stuck? the hints are right above and Reveal solution is one click away.
Implement hll_estimate(items, p): build m = 2^p registers of max ranks, then apply the HLL estimator with the small-range correction. The provided hash32 gives the bits; the top p select the register, the rest give the rank.
- For each item:
h = hash32(item). Bucket = top p bits (h >> (32 - p)). The remaining32 - pbits arew. - Rank = 1 + number of leading zeros of
wwithin its32 - pbits (ifwis all zeros, the rank is(32 - p) + 1). Keep the max rank per register. - Raw estimate:
alpha * m * m / ZwhereZ = Σ 2^(−register[j])andalpha = 0.7213 / (1 + 1.079/m). - Small-range correction: if the estimate ≤ 2.5·m and V registers are still zero, return
m * ln(m / V)instead. Truncate to an int.
Explore the topic
See this challenge alongside everything else on the same subject — handbooks, system designs, algorithms and tools, in one place.