题目:
请你为 最不经常使用(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