设计并实现最不经常使用(LFU)缓存的数据结构。它应该支持以下操作:get 和 put。
get(key) - 如果键存在于缓存中,则获取键的值(总是正数),否则返回 -1。
put(key, value) - 如果键不存在,请设置或插入值。当缓存达到其容量时,它应该在插入新项目之前,使最不经常使用的项目无效。在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,最近最少使用的键将被去除。
进阶:
你是否可以在 O(1) 时间复杂度内执行两项操作?
示例:
LFUCache cache = new LFUCache( 2 /* capacity (缓存容量) */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 去除 key 2
cache.get(2); // 返回 -1 (未找到key 2)
cache.get(3); // 返回 3
cache.put(4, 4); // 去除 key 1
cache.get(1); // 返回 -1 (未找到 key 1)
cache.get(3); // 返回 3
cache.get(4); // 返回 4
思路:我用了三个map加一个set搞定了这道题,其中:
set:按照升序存储频率值
map1:存储key和value的映射
map2:存储每种频率下所有的key
map3:存储key与该key出现的频率之间的映射
class LFUCache {
private int capacity,num;
private Set<Integer> st;
private Map<Integer,Integer> map1;
private Map<Integer,Integer> map3;
private Map<Integer,List<Integer>> map2;
public LFUCache(int capacity) {
num=0;
map1=new HashMap<>();
map2=new HashMap<>();
map3=new HashMap<>();
this.capacity=capacity;
st=new TreeSet<>((o1,o2)->o1-o2);
}
public int get(int key) {
//System.out.println(map1);
if(map1.containsKey(key)) {
Update(key);
return map1.get((Object)key);
}
return -1;
}
public void put(int key, int value) {
if(capacity==0) return;
if(map1.containsKey(key)) {
map1.put(key, value);
Update(key);
return;
}
num++;
map1.put(key, value);
map3.put(key, 1);
if(!st.contains(1))
st.add(1);
if(!map2.containsKey(1))
map2.put(1, new ArrayList<>());
map2.get(1).add(key);
//System.out.println(map2.get((Object)1));
if(num>capacity) {
//System.out.println(map2.get(p));
int p=st.iterator().next();
if(map2.get(p).size()==1 && map2.get(p).get(0)==key) p++;
while(!map2.containsKey(p) || map2.get(p).size()==0) p++;
//System.out.println(p+" " +map2.get(p));
int val=map2.get(p).get(0);
//System.out.print(val);
map1.remove((Object)val);
map2.get(p).remove((Object)val);
map3.remove((Object)val);
//System.out.println(map1);
num--;
}
}
private void Update(int key) {
int tmp=map3.get((Object)key);
map3.remove((Object)key);
map2.get((Object)tmp).remove((Object)key);
if(map2.get((Object)tmp).size()==0)
st.remove((Object)tmp);
if(!map2.containsKey((Object)(tmp+1)))
map2.put(tmp+1, new ArrayList<>());
map2.get((Object)(tmp+1)).add(key);
map3.put(key, tmp+1);
if(!st.contains((Object)(tmp+1))) st.add(tmp+1);
}
}