LFU Cache
Design a data structure that follows the constraints of a Least Frequently Used (LFU) cache. It must support O(1) time complexity for both get and put operations.
- 0 <= capacity <= 10⁴
- 0 <= key <= 10⁵
- 0 <= value <= 10⁹
- At most 2 × 10⁵ calls will be made to get and put
["LFUCache", "put", "put", "get", "put", "get", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [3], [4, 4], [1], [3], [4]][null, null, null, 1, null, -1, 3, null, -1, 3, 4]If LRU is a "Recency" policy, LFU is a "Popularity" policy. Imagine a library that tracks not just the most recently read books, but how many times each book has been read in total.
Instead of one long line, we organize books into Frequency Shelves.
- There is a shelf for books read 1 time, a shelf for 2 times, and so on.
- Each shelf is itself a Doubly Linked List (DLL) where new arrivals go to the front.
- If we access a book on the "Freq 1" shelf, it is immediately "promoted" to the front of the "Freq 2" shelf.
When the library is full and a new book arrives:
1. We look for the lowest-numbered shelf that isn't empty (the minFreq).
2. On that shelf, we take the book at the very back (the one that hasn't been touched in the longest time—the LRU of that frequency).
3. We evict it to make room.
To make this work at lightning speed, we use two maps:
- Map 1 (The Directory): Maps key -> Node. This lets us find any book instantly.
- Map 2 (The Shelves): Maps frequency -> DLL. This lets us find the "Freq 1" shelf or the "Freq 5" shelf instantly.
Hierarchical DLL Architecture
Hierarchy
- Frequency Buckets: Keys with the same access count stay together.
- Internal LRU: Each bucket is a DLL. We evict from the back of the lowest freq bucket.
Optimal Cache Policy
LFU is superior for frequency-heavy workloads. The hierarchical DLL structure ensures that both "promotion" and "eviction" take O(1) time.