LFU算法

思路

LFU每个freq对应的集合其实就是个LRU,淘汰K时,会首先选取freq最小的集合,其次选取最久未使用的Key。
更新或者查询时,会将对应的K/V从当前freq提升至freq+1集合的末尾(假如头代表最久未使用)。

插入

image

查询

image

代码实现

···
class LFUCache {

private int minFreq;

private int capacity;

private Map<Integer, Integer> keyToVal;

private Map<Integer, Integer> keyToFreq;

private Map<Integer, LinkedHashSet> 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 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);
    */
    ···
posted @ 2023-08-29 16:57  kiper  阅读(133)  评论(0)    收藏  举报