题意:设计并实现LFU缓存,需要支持get、set操作,二者的语义描述如下:
get(key):如果key在缓存中,返回值,否则返回-1;
set(key, value) :如果key不存在,插入(key, value)。注意问题:1、当缓存满时(达到缓存capacity),先淘汰掉最近使用最少的项;2、当多个key访问频率相同时,淘汰最近没被访问的key。
要求:set/get操作的时间复杂度为O(1)
思路:1、数据结构---->HashMap保存(key, value)映射,
2、淘汰策略实现-----> HashMap(key, <count,timespan>),其中count是key的访问频率,timespan是计数器表示访问时间,按照count比较优先,其次按照timespan比较,淘汰count、timespan最小的key,该操作的时间复杂度为O(n), 分摊成本为O(1/capacity)
ps:HashMap VS HashTable(HashMap implements Map, HashTable extends Dictionary; HashMap无同步实现,HashTable已实现同步,故HashMap是HashTable的轻量级实现)
import java.util.HashMap;
import java.util.Map;
public class LFUCache {
HashMap
map;
HashMap
lfu;
int counter = 0; //count #ops
int capacity;
public LFUCache(int capacity){
if(capacity == 0){
this.capacity = -1;
return;
}
this.capacity = capacity;
map = new HashMap<>(capacity);
lfu = new HashMap<>(capacity);
}
public void updateAttr(int key){
if(!lfu.containsKey(key)){
Attr value = new Attr(0, 0);
lfu.put(key, value);
}
Attr attr = lfu.get(key);
attr.count++;
attr.timespan = ++counter;
}
public int get(int key){
if(capacity < 0 || !map.containsKey(key))
return -1;
updateAttr(key);
return map.get(key);
}
public void set(int key, int value){
if(capacity < 0){
return;
}
if(map.containsKey(key)){
map.put(key, value); //replace old value with new one
updateAttr(key);
}else{
if(capacity == 0){//run out of cache space
Integer rev = findLeast();
map.remove(rev);
lfu.remove(rev);
capacity++;
}
map.put(key, value);
capacity--;
updateAttr(key);
}
}
public Integer findLeast(){
int key = 0;
Attr attr = new Attr(Integer.MAX_VALUE, 0);
for(Map.Entry
ety : lfu.entrySet()){
Attr lbe = ety.getValue();
if(attr.compareTo(lbe) > 0){
key = ety.getKey();
attr = lbe;
}
}
return key;
}
static class Attr implements Comparable
{
int count;
int timespan;
public Attr(int count, int timespan) {
super();
this.count = count;
this.timespan = timespan;
}
@Override
public int compareTo(Attr o) {
if(this.count - o.count != 0)
return this.count - o.count;
else{
return this.timespan - o.timespan;
}
}
}
}