LFU Cache

hard

Design a Least Frequently Used (LFU) cache with a fixed capacity:

  • LFUCache(capacity) — create the cache.
  • get(key) — return the value for key, or -1 if absent; a successful get increases the key's use frequency.
  • put(key, value) — insert or update key (also increasing its frequency). If the cache is over capacity, evict the least frequently used key; if several tie on frequency, evict the least recently used among them.

Both get and put must run in O(1) average time.

Hints

Evict by lowest use frequency, breaking ties by least recently used.
Group keys into one ordered bucket per frequency, and track the minimum frequency present.
Every access bumps a key up one bucket; eviction takes the LRU of the minimum-frequency bucket.

Common doubts

To evict the least-frequently-used key in O(1), you need instant access to all keys at the minimum frequency; a bucket per frequency provides exactly that.
Among the lowest-frequency keys, the tie-break is least-recently-used, so the bucket must be ordered by recency to evict the right one.
It increases by 1 only when a bump empties the current minimum bucket, and it resets to 1 whenever a brand-new key (frequency 1) is inserted.

Interview follow-ups

LRU tracks only recency (one ordered list); LFU tracks frequency first, then recency, needing a bucket per frequency plus a minFreq pointer.
Real LFU variants decay frequencies over time (e.g. Window-TinyLFU) to avoid stale keys dominating the cache forever.

Fun facts

  • LFU with the minFreq trick is a favorite hard design question precisely because the O(1) tie-break-by-recency is subtle.
  • Production caches often blend LRU and LFU (e.g. Caffeine's TinyLFU) to get the best of both.

Asked at

AmazonGoogleMicrosoftBloomberg
Frequently Sometimes Occasionally
Example 1
Input: capacity=2; put(1,1),put(2,2),get(1),put(3,3),get(2),get(3)
Output: 1, -1, 3
get(1) makes key 1 frequency 2; put(3,3) evicts key 2 (freq 1), so get(2)=-1 and get(3)=3.
Example 2
Input: capacity=0; put(0,0),get(0)
Output: -1
A zero-capacity cache stores nothing, so get returns -1.
Constraints

- 0 <= capacity <= 10^4 - 0 <= key <= 10^5 - 0 <= value <= 10^9 - At most 2 * 10^5 calls to get and put

Solve this problem →