460.LFU缓存
https://leetcode-cn.com/problems/lfu-cache/
与146.LRU缓存的区别在于,这里不止考虑时间,还要考虑频率,频率相同时才比较时间。
用两个简单map:keyToVal查值(put操作传入k和v),keyToFreq查频率(get操作需要增加k的频率,需要快速获取)
一个复杂map:freqToKeys,键为频率,值为相同频率的链表(使用java的LinkedHashSet),链表头就是最早加入的。删除key时,从这个map中找最小频率(用minFreq维护)对应的链表头删除,即满足题意。
注意minFreq只需要在freqToKeys表大小变化时更新,永远指向最小的key
class LFUCache {
// 用于快速查值。简称kv
private HashMap<Integer, Integer> keyToVal;
// 用于快速查频率。简称kf
private HashMap<Integer, Integer> keyToFreq;
// 用于频率相同时删最早的,简称fk
private HashMap<Integer, LinkedHashSet<Integer>> freqToKeys;
// 最小频率(用于标识fk表最小的key)
private int minFreq;
// 容量
private int cap;
// 初始化
public LFUCache(int capacity) {
keyToVal = new HashMap<>();
keyToFreq = new HashMap<>();
freqToKeys = new HashMap<>();
cap = capacity;
minFreq = 0;
}
// 对外get接口
public int get(int key) {
if (!keyToVal.containsKey(key)) {
return -1;
}
// 增加key对应的freq
increaseFreq(key);
return keyToVal.get(key);
}
// 对外put接口
public void put(int key, int value) {
if (this.cap == 0) return;
if (keyToVal.containsKey(key)) {
keyToVal.put(key, value);
// 增加key对应的freq
increaseFreq(key);
} else {
// key不存在
// 若容量已满,需要淘汰一个
if (this.cap <= keyToVal.size()) {
removeMinFreqKey();
}
keyToVal.put(key, value);
keyToFreq.put(key, 1);
// 插入fk表
// 若频率1不存在,给一个新的set;若存在则直接将key加入集合
freqToKeys.putIfAbsent(1, new LinkedHashSet<>());
freqToKeys.get(1).add(key);
// 更新最小频率
minFreq = 1;
}
}
private void removeMinFreqKey() {
// freq最小的key列表
LinkedHashSet<Integer> keyList = freqToKeys.get(this.minFreq);
// 列表第一个就是最早加入的key,应删除
int delKey = keyList.iterator().next();
// 更新fk表
keyList.remove(delKey);
if (keyList.isEmpty()) {
freqToKeys.remove(minFreq);
}
// 此处没必要更新minFreq,因为只有put操作调用本函数,而put会将minFreq置1
// 更新kv表和kf表
keyToVal.remove(delKey);
keyToFreq.remove(delKey);
}
private void increaseFreq(int key) {
// 先取key的freq
int freq = keyToFreq.get(key);
freqToKeys.get(freq).remove(key);
if (freqToKeys.get(freq).isEmpty()) {
freqToKeys.remove(freq);
if (minFreq == freq) {
minFreq++;
}
}
// 更新fk表
// 若频率freq+1不存在,给一个新的set;若存在则直接将key加入集合
freqToKeys.putIfAbsent(freq + 1, new LinkedHashSet<>());
freqToKeys.get(freq + 1).add(key);
// 更新kf表
keyToFreq.put(key, freq + 1);
}
public static void main(String[] args) {
LFUCache lFUCache = new LFUCache(0);
lFUCache.put(0, 0);
int a = lFUCache.get(0);
System.out.println(a);
}
}
最后更新于