Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
LFU Cache in Python
A Least Frequently Used (LFU) cache is a data structure that removes the least frequently accessed item when the cache reaches its maximum capacity. Python's collections.OrderedDict helps track both frequency and insertion order for efficient implementation.
LFU Cache Operations
The LFU cache supports two main operations:
get(key)- Returns the value if the key exists, otherwise returns -1put(key, value)- Inserts or updates a key-value pair
When capacity is reached, the cache removes the least frequently used element before inserting a new one.
Implementation Strategy
The implementation uses two data structures:
node_for_key- Maps keys to their values and frequenciesnode_for_freq- Groups keys by frequency using OrderedDict for insertion orderleast_freq- Tracks the minimum frequency for efficient eviction
Complete Implementation
import collections
class LFUCache:
def __init__(self, capacity):
self.remain = capacity
self.least_freq = 1
self.node_for_freq = collections.defaultdict(collections.OrderedDict)
self.node_for_key = dict()
def _update(self, key, value):
# Get current frequency and remove from current frequency group
_, freq = self.node_for_key[key]
self.node_for_freq[freq].pop(key)
# If least frequency group becomes empty, increment least_freq
if len(self.node_for_freq[self.least_freq]) == 0:
self.least_freq += 1
# Add to next frequency group
self.node_for_freq[freq + 1][key] = (value, freq + 1)
self.node_for_key[key] = (value, freq + 1)
def get(self, key):
if key not in self.node_for_key:
return -1
value = self.node_for_key[key][0]
self._update(key, value)
return value
def put(self, key, value):
if self.remain == 0:
return
if key in self.node_for_key:
# Update existing key
self._update(key, value)
else:
# Insert new key with frequency 1
self.node_for_key[key] = (value, 1)
self.node_for_freq[1][key] = (value, 1)
if self.remain == 0:
# Remove least frequently used item
removed = self.node_for_freq[self.least_freq].popitem(last=False)
self.node_for_key.pop(removed[0])
else:
self.remain -= 1
self.least_freq = 1
# Example usage
cache = LFUCache(2)
cache.put(1, 1)
cache.put(2, 2)
print(cache.get(1)) # Returns 1, frequency of key 1 becomes 2
cache.put(3, 3) # Evicts key 2 (least frequent)
print(cache.get(2)) # Returns -1 (key 2 was evicted)
cache.put(4, 4) # Evicts key 3 (least frequent)
print(cache.get(1)) # Returns 1
print(cache.get(3)) # Returns -1 (key 3 was evicted)
print(cache.get(4)) # Returns 4
1 -1 1 -1 4
How It Works
The algorithm maintains frequency groups using OrderedDict to preserve insertion order within each frequency level. When a key is accessed:
Its frequency increases by 1
It moves to the next frequency group
If the current least frequency group becomes empty,
least_freqis incremented
When eviction is needed, the first item from the least frequency group is removed using FIFO order.
Time Complexity
| Operation | Time Complexity | Space Complexity |
|---|---|---|
get() |
O(1) | O(capacity) |
put() |
O(1) | O(capacity) |
Conclusion
The LFU cache efficiently manages memory by tracking access frequencies using OrderedDict. Both get and put operations run in O(1) time, making it suitable for high-performance applications requiring intelligent caching strategies.
