1. 程式人生 > >LFU緩存

LFU緩存

lee 復雜度 leetcode println -c add https 時間復雜度 AI

https://leetcode-cn.com/problems/lfu-cache/description/

緩存的實現可以采取多種策略,不同策略優點的評估就是“命中率”。好的策略可以實現較高的命中率。常用的策略如:LRU(最近最少使用)、LFU(最不頻繁使用)。這兩種策略都可以在O(1)時間內實現get和put。本文主要講講LFU的實現。

import java.util.HashMap;
import java.util.LinkedHashSet;

class LFUCache {
    
    public int capacity;//容量大小
    public HashMap<Integer, Integer> map = new HashMap<>();//存儲put進去的key和value
    public HashMap<Integer, Integer> frequent = new HashMap<>();//存儲每個key的頻率值
    //存儲每個頻率的相應的key的值的集合,這裏用HashSet是因為其是由HashMap底層實現的,可以O(1)時間復雜度查找元素
    //而且linked是有序的,同一頻率值越往後越最近訪問
    public HashMap<Integer, LinkedHashSet<Integer>> list = new HashMap<>();
    int min = -1;//標記當前頻率中的最小值
    
    public LFUCache(int capacity) {
        this.capacity = capacity;
    }
    
    
    public int get(int key) {
        if(!map.containsKey(key)){
            return -1;
        }else{
            int value = map.get(key);//獲取元素的value值
            int count = frequent.get(key);
            frequent.put(key, count + 1);
            
            list.get(count).remove(key);//先移除當前key
            
            //更改min的值
            if(count == min && list.get(count).size() == 0)
                min++;
            
            LinkedHashSet<Integer> set = list.containsKey(count + 1) ? list.get(count + 1) : new LinkedHashSet<Integer>();
            set.add(key);
            list.put(count + 1, set);
            
            return value;
        }
        
    }
    
    public void put(int key, int value) {
        if(capacity <= 0){
            return;
        }
        //這一塊跟get的邏輯一樣
        if(map.containsKey(key)){
            map.put(key, value);
            int count = frequent.get(key);
            frequent.put(key, count + 1);
            
            list.get(count).remove(key);//先移除當前key
            
            //更改min的值
            if (count == min && list.get(count).size() == 0)
                min++;
            
            LinkedHashSet<Integer> set = list.containsKey(count + 1) ? list.get(count + 1) : new LinkedHashSet<Integer>();
            set.add(key);
            list.put(count + 1, set);
        }else{
            if(map.size() >= capacity){
                Integer removeKey = list.get(min).iterator().next();
                list.get(min).remove(removeKey);
                map.remove(removeKey);
                frequent.remove(removeKey);
            }
            map.put(key, value);
            frequent.put(key, 1);
            LinkedHashSet<Integer> set = list.containsKey(1) ? list.get(1) : new LinkedHashSet<Integer>();
            set.add(key);
            list.put(1, set);
            
            min = 1;
        }
        
    }
    
    public static void main(String[] args) {
        LFUCache lfuCache = new LFUCache(2);
        lfuCache.put(2, 1);
        lfuCache.put(3, 2);
        System.out.println(lfuCache.get(3));
        System.out.println(lfuCache.get(2));
        lfuCache.put(4, 3);
        System.out.println(lfuCache.get(2));
        System.out.println(lfuCache.get(3));
        System.out.println(lfuCache.get(4));
    }
}

參考資料

http://www.cnblogs.com/DarrenChan/p/8819996.html

LFU緩存