【データ構造】 460. LFUキャッシュ

460. LFUキャッシュ

問題解決のアイデア

  • get オペレーションは、キーに対応する val を返し、対応する freq を追加します。
  • 挿入操作では、キーが既に存在する場合は直接更新し、キーが存在しないがコンテナがいっぱいの場合は、頻度が最も小さいキーを削除してから挿入します。

class LFUCache {
    
    
           // key到  val的映射   KV
        HashMap<Integer,Integer> keyToVal;

        // 从key到freq的映射  KF
        HashMap<Integer,Integer> keyToFreq;

        // 一个频率对应多个 key  舍弃最久未使用的  FK
        HashMap<Integer,LinkedHashSet<Integer>> freqToKeys;
        // 记录最小的频率
        int minFreq;

        // 记录LFU 缓存的最大容量
        int cap;

    public LFUCache(int capacity) {
    
    
        keyToVal = new HashMap<>();
        keyToFreq = new HashMap<>();
        freqToKeys = new HashMap<>();
        this.cap = capacity;
        this.minFreq = 0;
    }
    // 返回对应key的val  然后增加对应的freq
    public int get(int key) {
    
    

        if(!keyToVal.containsKey(key)){
    
    
            return -1;// 返回-1  说明没找到
        }

        // 增加key对应的freq + 1  因为查找操作一次
        increaseFreq(key);
        return keyToVal.get(key);// 找到val

    }

    public void put(int key, int value) {
    
    
        // 如果key 已经存在直接更新

        if(this.cap <= 0){
    
    
            return;
        }

        if(keyToFreq.containsKey(key)){
    
    
            // 修改val即可
            keyToVal.put(key,value);
            // 对应的freq加一
            increaseFreq(key);

            return;
        }


        // key 不存在  需要插入 如果容量没有满 直接插入  如果已满 直接删除 freq最小的key


        if(this.cap <= keyToVal.size()){
    
    
            removeMinFreqKey();// 删除freq最小的key
        }


        keyToVal.put(key,value);

        keyToFreq.put(key,1);

        // 插入KF 表  一种freq对应多种key
        freqToKeys.putIfAbsent(1,new LinkedHashSet<>());


        freqToKeys.get(1).add(key);// 获取频率  添加一种key

        // 插入新的key之后最小的freq肯定是1

        this.minFreq = 1;


    }


    private void removeMinFreqKey(){
    
    
        // freq最小的key列表  通过 FK
        LinkedHashSet<Integer> keyList = freqToKeys.get(this.minFreq);// 获取所有的key

        // 最先被插入的key就是该被淘汰的key
        int deleteKey = keyList.iterator().next();

        // 更新FK 
        keyList.remove(deleteKey);

        if(keyList.isEmpty()){
    
    
            // 如果key列表是空的  说明都没有了直接删除freq
            freqToKeys.remove(this.minFreq);
        }

        // 更新KV
        keyToVal.remove(deleteKey);

        // 更新KF
        keyToFreq.remove(deleteKey);

    }

    private void increaseFreq(int key){
    
    
        int freq = keyToFreq.get(key);

        // 更新 KF
        keyToFreq.put(key,freq + 1);

        // 更新FK

        // 将key 从freq对应的列表中删除
        freqToKeys.get(freq).remove(key);

        // 将key加入freq + 1 对应的列表
        freqToKeys.putIfAbsent(freq + 1,new LinkedHashSet<>());// 创建新的
        freqToKeys.get(freq + 1).add(key);

        // 如果对应的列表空
        if(freqToKeys.get(freq).isEmpty()){
    
    
            freqToKeys.remove(freq);
            if(freq == this.minFreq){
    
    
                this.minFreq++;
            }
        }
    }
}

/**
 * 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);
 */

おすすめ

転載: blog.csdn.net/qq_44653420/article/details/133460987