leetcode460. LFU Cache

题目要求

Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the following operations: get and put.java

get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(key, value) - Set or insert the value if the key is not already present. When the cache reaches its capacity, it should invalidate the least frequently used item before inserting a new item. For the purpose of this problem, when there is a tie (i.e., two or more keys that have the same frequency), the least recently used key would be evicted.算法

Note that the number of times an item is used is the number of calls to the get and put functions for that item since it was inserted. This number is set to zero when the item is removed.缓存

Follow up:
Could you do both operations in O(1) time complexity?性能

Example:this

LFUCache cache = new LFUCache( 2 /* capacity */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // returns 1
cache.put(3, 3);    // evicts key 2
cache.get(2);       // returns -1 (not found)
cache.get(3);       // returns 3.
cache.put(4, 4);    // evicts key 1.
cache.get(1);       // returns -1 (not found)
cache.get(3);       // returns 3
cache.get(4);       // returns 4

要求实现一个缓存,该缓存要求具有一个字典的基本能力,而且其淘汰算法基于LFU(Least Frequently Used 最近使用次数最少原则)。设计

简单介绍一下LFU。LFU是指put新的元素时,一旦当前缓存的数量达到上限,就按照最近访问次数从低到高开始淘汰缓存中现有的元素。put和get操做都会增长访问次数。若是淘汰时出现多个访问次数相同的key时,则按照LRU来操做,即优先淘汰最近一次访问间隔最远的元素。code

思路和代码

根据上面的思路咱们知道,在设计这个缓存的时候,咱们一共须要记录三个信息:队列

  1. key-val映射,知足缓存的基本要求
  2. key-count映射,记录当前的key最近被访问的次数
  3. 一样访问频率下key最后一次访问的前后次序(为了知足LRU淘汰策略),这里引入了LinkedHashSet来知足这个要求。

简单介绍一下LinkedHashSet。LinkedHashSet首先知足Set的基本要求,即位于该集合中的元素不会重复。其次,它会记录元素加入集合中的顺序,底层的话实际上是经过链表来存储,所以加入元素至链表末端或者是从链表头取出元素的性能成本都很低。ci

代码以下:rem

HashMap<Integer, Integer> vals;  
HashMap<Integer, Integer> counts;  
HashMap<Integer, LinkedHashSet<Integer>> lists;  
int cap;  
int min = -1;  
public LFUCache(int capacity) {  
    cap = capacity;  
    vals = new HashMap<>();  
    counts = new HashMap<>();  
    lists = new HashMap<>();  
    lists.put(1, new LinkedHashSet<>());  
}  
  
public int get(int key) {  
    if(!vals.containsKey(key)) {  
        return -1;  
    }  
    int count = counts.get(key);  
    counts.put(key, count+1);  
    lists.get(count).remove(key);  
    if(count==min && lists.get(count).size()==0) {  
        min++;  
    }  
    if(!lists.containsKey(count+1)) {  
        lists.put(count + 1, new LinkedHashSet<>());  
    }  
    lists.get(count+1).add(key);  
    return vals.get(key);  
}  
  
public void put(int key, int value) {  
    if(cap<=0) {  
        return;  
    }  
    if(vals.containsKey(key)) {  
        vals.put(key, value);  
        get(key);  
        return;  
    }  
    if(vals.size() >= cap) {  
        int evit = lists.get(min).iterator().next();  
        lists.get(min).remove(evit);  
        vals.remove(evit);  
    }  
    vals.put(key, value);  
    counts.put(key, 1);  
    min = 1;  
    lists.get(1).add(key);  
}

这里经过min这个值记录当前的最低访问次数,从而在执行淘汰算法的时候能够直接从对应访问次数的队列中直接删除。

相关文章
相关标签/搜索