LeetCode 460: LFU Cache (Hash Map + Frequency Buckets)
LeetCode 460DesignHash MapToday we solve LeetCode 460 - LFU Cache.
Source: https://leetcode.com/problems/lfu-cache/
English
Problem Summary
Design a cache with average O(1) get/put. On overflow, evict lowest frequency, and if tie, evict least recently used inside that frequency.
Key Idea
Maintain key→node and freq→doubly linked list. Each frequency list is LRU ordered. Keep minFreq for O(1) eviction bucket lookup.
Reference Implementations (Java / Go / C++ / Python / JavaScript)
class LFUCache {
private final int cap;
private int minFreq = 0;
private final Map val = new HashMap<>();
private final Map freq = new HashMap<>();
private final Map> bucket = new HashMap<>();
public LFUCache(int capacity) { this.cap = capacity; }
public int get(int key) {
if (!val.containsKey(key)) return -1;
touch(key);
return val.get(key);
}
public void put(int key, int value) {
if (cap == 0) return;
if (val.containsKey(key)) {
val.put(key, value);
touch(key);
return;
}
if (val.size() == cap) {
int evict = bucket.get(minFreq).iterator().next();
bucket.get(minFreq).remove(evict);
val.remove(evict);
freq.remove(evict);
}
val.put(key, value);
freq.put(key, 1);
bucket.computeIfAbsent(1, k -> new LinkedHashSet<>()).add(key);
minFreq = 1;
}
private void touch(int key) {
int f = freq.get(key);
bucket.get(f).remove(key);
if (f == minFreq && bucket.get(f).isEmpty()) minFreq++;
freq.put(key, f + 1);
bucket.computeIfAbsent(f + 1, k -> new LinkedHashSet<>()).add(key);
}
} // Same design: key->value/freq, freq->ordered keys, minFreq updates in O(1).// Same design: unordered_map + list per frequency + minFreq.from collections import defaultdict, OrderedDict
class LFUCache:
def __init__(self, capacity: int):
self.cap = capacity
self.minf = 0
self.kv = {}
self.fk = defaultdict(OrderedDict)
def _touch(self, k):
v, f = self.kv[k]
del self.fk[f][k]
if not self.fk[f]:
del self.fk[f]
if self.minf == f:
self.minf += 1
self.kv[k] = (v, f + 1)
self.fk[f + 1][k] = None
def get(self, key: int) -> int:
if key not in self.kv: return -1
self._touch(key)
return self.kv[key][0]
def put(self, key: int, value: int) -> None:
if self.cap == 0: return
if key in self.kv:
self.kv[key] = (value, self.kv[key][1])
self._touch(key)
return
if len(self.kv) == self.cap:
k, _ = self.fk[self.minf].popitem(last=False)
del self.kv[k]
self.kv[key] = (value, 1)
self.fk[1][key] = None
self.minf = 1// Same design: Map key->(value,freq), Map freq->ordered keys, with minFreq.中文
题目概述
设计 LFU 缓存,要求 get/put 平均 O(1)。满容量时先淘汰最小频次,频次相同再淘汰该频次里最久未使用。
核心思路
维护 key→节点,freq→双向/有序链表(内部 LRU 顺序),并记录 minFreq,保证淘汰和晋升都能 O(1) 完成。
多语言参考实现(Java / Go / C++ / Python / JavaScript)
class LFUCache {
private final int cap;
private int minFreq = 0;
private final Map val = new HashMap<>();
private final Map freq = new HashMap<>();
private final Map> bucket = new HashMap<>();
public LFUCache(int capacity) { this.cap = capacity; }
public int get(int key) {
if (!val.containsKey(key)) return -1;
touch(key);
return val.get(key);
}
public void put(int key, int value) {
if (cap == 0) return;
if (val.containsKey(key)) {
val.put(key, value);
touch(key);
return;
}
if (val.size() == cap) {
int evict = bucket.get(minFreq).iterator().next();
bucket.get(minFreq).remove(evict);
val.remove(evict);
freq.remove(evict);
}
val.put(key, value);
freq.put(key, 1);
bucket.computeIfAbsent(1, k -> new LinkedHashSet<>()).add(key);
minFreq = 1;
}
private void touch(int key) {
int f = freq.get(key);
bucket.get(f).remove(key);
if (f == minFreq && bucket.get(f).isEmpty()) minFreq++;
freq.put(key, f + 1);
bucket.computeIfAbsent(f + 1, k -> new LinkedHashSet<>()).add(key);
}
} // 同思路:key->value/freq,freq->有序键集合,minFreq O(1) 维护。// 同思路:unordered_map + 每个频次一个链表 + minFreq。from collections import defaultdict, OrderedDict
class LFUCache:
def __init__(self, capacity: int):
self.cap = capacity
self.minf = 0
self.kv = {}
self.fk = defaultdict(OrderedDict)
def _touch(self, k):
v, f = self.kv[k]
del self.fk[f][k]
if not self.fk[f]:
del self.fk[f]
if self.minf == f:
self.minf += 1
self.kv[k] = (v, f + 1)
self.fk[f + 1][k] = None
def get(self, key: int) -> int:
if key not in self.kv: return -1
self._touch(key)
return self.kv[key][0]
def put(self, key: int, value: int) -> None:
if self.cap == 0: return
if key in self.kv:
self.kv[key] = (value, self.kv[key][1])
self._touch(key)
return
if len(self.kv) == self.cap:
k, _ = self.fk[self.minf].popitem(last=False)
del self.kv[k]
self.kv[key] = (value, 1)
self.fk[1][key] = None
self.minf = 1// 同思路:Map key->(value,freq), Map freq->有序键,minFreq 常数维护。
Comments