Why is hash-table lookup called expected O(1) rather than simply O(1)?
answer
- one letter, three different promises
- average over what, exactly
- what if every key lands together
- chain length tracks the load factor
- expected, worst-case, amortized
basics
~20 sHash-table lookup is constant time only on average, assuming keys spread evenly across buckets. When many keys land in the same bucket the lookup walks that bucket instead, so the worst case is O(n) in the number of stored entries.
solid answer
~40 sThree qualifiers travel with hash-table costs, and dropping them is the classic screen-out. Lookup is **expected** O(1): if keys are equally likely to land in any bucket, the average bucket holds the load factor's worth of entries, so a constant number of probes finds the key. **Worst case** is O(n): if every key hashes to one bucket, the table has degenerated into a single linear scan. Insert is **amortized** O(1): most inserts touch one slot, but the insert that triggers growth rehashes every live entry, and that cost is spread over the inserts before it. So the honest sentence is "expected O(1) lookup, O(n) worst case, amortized O(1) insert" — and each qualifier names a different thing that has to be true.
go deeper
Be ready to say all three qualifiers unprompted: expected O(1) lookup, O(n) worst case, amortized O(1) insert. Interviewers listen for whether you add them yourself or only after being pushed.
Explain where "expected" comes from — keys scattering across buckets so the average bucket holds the load factor's worth of entries — and describe exactly what the table looks like when that fails.
Show which qualifier matters for the workload on the table. A batch job cares about the total across a sequence; a request path with a deadline is judged on its slowest single operation, so the worst case is the number to defend.
Own the standard that a cost claim without its condition is not reviewable. Push design docs to write bounds with the qualifier and the assumption attached, so capacity and latency arguments can be checked rather than believed.
## What the plain claim hides "Hash lookups are O(1)" is the most repeated sentence in interview prep and the most incomplete. Big-O is a bound on a cost function, but it says nothing on its own about *which* cost function: the cost of one operation on the worst possible input, the cost averaged over some distribution, or the cost of a whole sequence divided by its length. A hash table needs all three answers, because it gives a different one to each question. ## Expected O(1): what "expected" averages over The standard analysis assumes *simple uniform hashing*: each stored key is equally likely to hash to any of the `m` buckets, independently of the others. Let `n` be the number of entries and `alpha = n/m` the load factor. Under that assumption the expected number of entries sharing a bucket with your key is `alpha`, so a chained lookup costs `Theta(1 + alpha)` expected — hash once, then walk a chain whose expected length is a constant as long as the table keeps `alpha` bounded (which is exactly what growing on a load-factor threshold buys). That is where the O(1) comes from: not from magic, but from a bounded load factor plus an assumption about how keys scatter. Note what "expected" does *not* say. It does not say your next lookup is fast — expectation is an average over the key-to-bucket distribution, and any individual lookup may probe a long chain. It also does not say collisions are absent. Collisions are expected and routine; by the birthday effect a table with only a few dozen keys in a few hundred buckets already has them. Constant time survives collisions precisely because the *number* of collisions per bucket stays small on average. ## Worst case O(n): the degenerate table If every stored key hashes to the same bucket, chaining leaves you with one list of `n` entries and lookup becomes a linear scan: O(n). Open addressing degrades the same way — with all keys clustered, probing walks a long occupied run. Nothing about the data structure prevents this; it is prevented by the hash function scattering the particular keys you store. So the worst case is real, it is O(n), and the correct thing to say in an interview is that it is *unlikely under a well-mixing hash on ordinary keys*, not that it cannot happen. The direction of the claim matters. O(n) is an upper bound on the bad case, not a prediction; a table with a decent hash essentially never exhibits it. Equally, expected O(1) is an average, not a per-operation guarantee. Candidates who collapse either direction — "so it is really O(n)" or "so it is really O(1)" — get pushed on. ## Amortized O(1): the insert that pays for everyone A table that grows when the load factor crosses a threshold must, at that moment, allocate a bigger array and re-place every live entry: `Theta(n)` work in one call. Yet insert is still described as amortized O(1), because with growth by a constant *factor* the total re-placement work across `n` inserts is a geometric series — roughly `1 + 2 + 4 + ... + n < 2n` — so `n` inserts cost `O(n)` in total. Amortized is a statement about a worst-case *sequence*, and it is a different qualifier from expected: put together, an insert is expected amortized O(1), with a single insert able to cost `Theta(n)` for the growth and, in the degenerate case, more for a long chain. ## Why interviewers keep asking The question is a proxy for whether you state assumptions. Real runtimes differ on the details underneath the same bound — Java's hash map chains entries per bucket while Python's dict uses open addressing with a perturbed probe sequence — and the asymptotic story above holds for both, which is exactly why the qualifiers, not the implementation trivia, are what the analysis rests on. A good habit for design docs and whiteboards: write the bound with its condition attached. "Lookup expected O(1) with a bounded load factor; O(n) worst case if keys cluster; insert amortized O(1) because growth is by a constant factor." That sentence is reviewable. "O(1)" is not.
- A design doc says "lookups and inserts are O(1)". Rewrite that claim precisely."Lookup and delete are expected O(1) while the load factor stays bounded, and O(n) worst case if the stored keys cluster into one bucket. Insert is expected amortized O(1): the insert that crosses the growth threshold re-places every live entry in Theta(n), and growth by a constant factor spreads that over the preceding inserts." The rewrite names the condition for each bound, so a reviewer can argue with it.
- Does a perfect hash function make lookup worst-case O(1)?Yes, but only for a fixed, known-in-advance key set. A perfect hash maps that specific set to distinct slots with no collisions, so lookup is worst-case O(1) rather than expected O(1). The catch is that it must be constructed for the exact key set and rebuilt when keys change, which is why it suits static lookup tables and not general-purpose containers.
- If collisions are expected and normal, why does anyone care about the worst case?Because the worst case is what the tail of a latency distribution is made of, and because it is reachable — not by chance, but by keys whose structure the hash fails to mix, or by an input source you do not control. Expected O(1) is an average over key placement; a service that must meet a per-request deadline is judged on its slowest operations, not its mean.
saying these in an interview costs you the question
- Hash lookups are O(1), full stop
- Expected O(1) means every individual lookup is constant time
- The worst case is purely theoretical and never occurs
- Constant time requires that no two keys ever collide
- Expected and amortized are the same qualifier