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<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);
    */
    ···
posted @ 2023-08-29 16:57  kiper  阅读(50)  评论(0编辑  收藏  举报