LFU算法
思路
LFU每个freq对应的集合其实就是个LRU,淘汰K时,会首先选取freq最小的集合,其次选取最久未使用的Key。
更新或者查询时,会将对应的K/V从当前freq提升至freq+1集合的末尾(假如头代表最久未使用)。
插入
查询
代码实现
···
class LFUCache {
private int minFreq;
private int capacity;
private Map<Integer, Integer> keyToVal;
private Map<Integer, Integer> keyToFreq;
private Map<Integer, LinkedHashSet<Integer>> freqToKeys;
public LFUCache(int capacity) {
this.capacity = capacity;
this.minFreq = 0;
keyToVal = new HashMap<>();
keyToFreq = new HashMap<>();
freqToKeys = new HashMap<>();
}
public int get(int key) {
if (!keyToVal.containsKey(key)) return -1;
increaseFreq(key);
return keyToVal.get(key);
}
public void put(int key, int value) {
if (capacity <= 0) return;
if (keyToVal.containsKey(key)) {
keyToVal.put(key, value);
increaseFreq(key);
return;
}
if (keyToVal.size() == capacity) {
removeMinKey();
}
keyToVal.put(key, value);
keyToFreq.put(key, 1);
freqToKeys.compute(1, (k, v) -> v == null? new LinkedHashSet<>(): v).add(key);
minFreq = 1;
}
private void increaseFreq(int key) {
int freq = keyToFreq.get(key);
freqToKeys.get(freq).remove(key);
if (freqToKeys.get(freq).isEmpty()) {
freqToKeys.remove(freq);
if (freq == minFreq)
minFreq++;
}
keyToFreq.put(key, freq + 1);
freqToKeys.compute(freq + 1, (k, v) -> v == null? new LinkedHashSet<>(): v).add(key);
}
private void removeMinKey() {
LinkedHashSet<Integer> set = freqToKeys.get(minFreq);
int key = set.iterator().next();
set.remove(key);
if (set.isEmpty()) {
freqToKeys.remove(minFreq);
}
keyToVal.remove(key);
keyToFreq.remove(key);
}
}
/**
- Your LFUCache object will be instantiated and called as such:
- LFUCache obj = new LFUCache(capacity);
- int param_1 = obj.get(key);
- obj.put(key,value);
*/
···