题目:
请你为 最不经常使用(LFU)缓存算法设计并实现数据结构。它应该支持以下操作:get?和?put。
get(key)?- 如果键存在于缓存中,则获取键的值(总是正数),否则返回 -1。
put(key, value)?- 如果键不存在,请设置或插入值。当缓存达到其容量时,则应该在插入新项之前,使最不经常使用的项无效。在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,应该去除 最近 最少使用的键。
「项的使用次数」就是自插入该项以来对其调用 get 和 put 函数的次数之和。使用次数会在对应项被移除后置为 0 。
题解:
这题其实不会做... 先记录 有机会重新写过
struct Node {
int key, val, fre;
Node(int x, int y, int z): key(x), val(y), fre(z) {}
};
class LFUCache {
public:
int cap, minfreq;
unordered_map<int, list<Node>::iterator> stuff;
unordered_map<int, list<Node>> fre_table;
LFUCache(int capacity) {
cap = capacity;
minfreq = 0;
stuff.clear(); fre_table.clear();
}
int get(int key) {
if(cap == 0) return -1;
auto it = stuff.find(key);
if (it == stuff.end()) return -1;
// 有数值
list<Node>::iterator node = it->second;
int val = node->val, fre = node->fre;
fre_table[fre].erase(node); //将该节点修改频率哈希表,应存入+1处
if(fre_table[fre].size() == 0) {
fre_table.erase(fre); //直接把链表删除
if (minfreq == fre) minfreq += 1;
}
// 插入
fre_table[fre + 1].push_front(Node(key, val, fre + 1));
stuff[key] = fre_table[fre + 1].begin(); //新节点插入节点头
return val;
}
void put(int key, int value) {
if(cap == 0) return;
auto it = stuff.find(key);
if(it == stuff.end()) {
if(stuff.size() == cap) { //缓存已满
auto it2 = fre_table[minfreq].back(); //旧在末尾
stuff.erase(it2.key);
fre_table[minfreq].pop_back();
if(fre_table[minfreq].size() == 0) fre_table.erase(minfreq);
}
fre_table[1].push_front(Node(key, value, 1));
stuff[key] = fre_table[1].begin();
minfreq = 1;
} else {
list<Node>::iterator node = it->second;
int fre = node->fre;
fre_table[fre].erase(node);
if(fre_table[fre].size() == 0) {
fre_table.erase(fre);
if(minfreq == fre) minfreq += 1;
}
fre_table[fre + 1].push_front(Node(key, value, fre + 1));
stuff[key] = fre_table[fre + 1].begin();
}
}
};
/**
* 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);
*/
原文:https://www.cnblogs.com/recoverableTi/p/12641390.html