LFU Cache
Implement a Least Frequently Used (LFU) cache with O(1) get and put using a frequency-bucket map plus per-bucket doubly linked lists.
By CodeSnatch
November 29, 2025
·
Updated May 20, 2026
1,033 views
5
4.3 (17)
I had this on a Stripe systems-design phone screen as the algorithms portion. The interviewer specifically wanted O(1) for both get and put, which rules out the naive "scan all keys for the lowest count" approach. The textbook answer is the dual-map design: a key->node map for O(1) lookup, plus a frequency->doubly-linked-list map so eviction at minFreq and frequency bumps are also O(1).
LFU Cache
Design and implement a data structure for a Least Frequently Used (LFU) cache.
Implement the LFUCache class:
LFUCache(int capacity)initializes the object with thecapacityof the data structure.int get(int key)gets the value of the key if the key exists in the cache. Otherwise, returns-1.void put(int key, int value)updates the value of the key if present, or inserts the key if not already present. When the cache reaches itscapacity, it should invalidate and remove the LEAST FREQUENTLY USED key before inserting a new item. For this problem, when there is a tie (i.e., two or more keys with the same frequency), the LEAST RECENTLY USED key would be invalidated.
To determine the least frequently used key, a USE COUNTER is maintained for each key in the cache. The key with the smallest USE COUNTER is the least frequently used key.
When a key is first inserted into the cache, its USE COUNTER is set to 1 (due to the put operation). The USE COUNTER for a key in the cache is incremented when either a get or put operation is called on it.
The functions get and put must each run in O(1) average time complexity.
Examples
Example 1:
LFUCache lfu = new LFUCache(2);
lfu.put(1, 1); // cache = [1=1], freq: {1=1}
lfu.put(2, 2); // cache = [1=1, 2=2], freq: {1=1, 2=1}
lfu.get(1); // returns 1; cache = [2=2, 1=1], freq: {1=2, 2=1}
lfu.put(3, 3); // evicts key 2 (freq 1, LRU); cache = [1=1, 3=3], freq: {1=2, 3=1}
lfu.get(2); // returns -1 (not found)
lfu.get(3); // returns 3; cache = [1=1, 3=3], freq: {1=2, 3=2}
lfu.put(4, 4); // evicts key 1 (tie at freq=2, but 1 is LRU); cache = [3=3, 4=4], freq: {3=2, 4=1}
lfu.get(1); // returns -1 (not found)
lfu.get(3); // returns 3; freq: {3=3, 4=1}
lfu.get(4); // returns 4; freq: {3=3, 4=2}Constraints
1 <= capacity <= 10^4.0 <= key <= 10^5.0 <= value <= 10^9.- At most
2 * 10^5calls will be made togetandput.
Follow-up
Why two maps and not one? Because LFU eviction needs both "find lowest frequency" and "within that frequency, find oldest" in O(1). A single map only gives you O(n) for either of those. The frequency->DLL map plus a minFreq counter is the standard trick.
Solution
Starter code, test cases, and solutions are locked.
Purchase this item to access the full workspace.
