@(labuladong的算法小抄)[哈希链表]
leetcode 460. LFU 缓存
题目描述
解题思路
参考:labuladong的算法小抄P227
三个哈希表
用自顶向下的思考方法
首先,明确数据结构,即三个哈希表:
然后,列出get
和put
函数的需求:
最后,根据需求,明确三个函数:
class LFUCache {
HashMap<Integer, Integer> keyToVal, keyToFreq;
HashMap<Integer, LinkedHashSet<Integer>> freqToKeys;
//记录最小的freq
int minFreq;
//记录LFU缓存的最大容量
int cap;
public LFUCache(int capacity) {
keyToVal = new HashMap<>();
keyToFreq = new HashMap<>();
freqToKeys = new HashMap<>();
this.cap = capacity;
this.minFreq = 0;
}
public int get(int key) {
if (!keyToVal.containsKey(key)) {
return -1;
}
//增加key对应的freq
increaseFreq(key);
return keyToVal.get(key);
}
public void put(int key, int value) {
/* 插入判满 */
if (this.cap <= 0) return;
/* 如果key存在 */
if (keyToVal.containsKey(key)) {
//增加key对应的freq
increaseFreq(key);
//直接修改对应的val
keyToVal.put(key, value);
return;
}
/* 如果key不存在,需要插入 */
//如果容量满了,则需要先淘汰一个freq最小的key
if (keyToVal.size() >= this.cap) {
removeMinFreq();
}
//插入key value并修改key对应的freq加1
addKey(key, value);
}
/* 插入key value并修改key对应的freq加1 */
private void addKey(int key, int value) {
/* 更新KV表 */
keyToVal.put(key, value);
/* 更新KF表 */
keyToFreq.put(key, 1);
/* 更新FK表 */
freqToKeys.putIfAbsent(1, new LinkedHashSet<>());
freqToKeys.get(1).add(key);
/* 插入后key最小的freq肯定是1 */
this.minFreq = 1;
}
/* 淘汰一个freq最小的key */
private void removeMinFreq() {
//freq最小的key列表
LinkedHashSet<Integer> keyList = freqToKeys.get(this.minFreq);
//最先被插入的表头的key就是需要被淘汰的key
int removedKey = keyList.iterator().next();
/* 更新KF表 */
keyList.remove(removedKey);
if (keyList.isEmpty()) {
freqToKeys.remove(this.minFreq);
}
/* 更新KV表 */
keyToVal.remove(removedKey);
/* 更新KF表 */
keyToFreq.remove(removedKey);
}
/* 增加key对应的freq */
private void increaseFreq(int key) {
int freq = keyToFreq.get(key);
/* 更新KF表 */
keyToFreq.put(key, freq + 1);
/* 更新FK表 */
//将key从freq对应的列表中删除
freqToKeys.get(freq).remove(key);
//将key添加到freq+1对应的列表中
freqToKeys.putIfAbsent(freq + 1, new LinkedHashSet<>());
freqToKeys.get(freq + 1).add(key);
//如果freq对应的列表空了,移除这个freq
if (freqToKeys.get(freq).isEmpty()) {
freqToKeys.remove(freq);
//如果这个freq恰好是minFreq,则更新minFreq
if (freq == this.minFreq) {
this.minFreq++;
}
}
}
}
/**
* Your LFUCache object will be instantiated and called as such:
* LFUCache obj = new LFUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/