# LFU 缓存

请你为 最不经常使用(LFU)缓存算法设计并实现数据结构。

实现 LFUCache 类:

注意「项的使用次数」就是自插入该项以来对其调用 getput 函数的次数之和。使用次数会在对应项被移除后置为 0 。

为了确定最不常使用的键,可以为缓存中的每个键维护一个 使用计数器 。使用计数最小的键是最久未使用的键。

当一个键首次插入到缓存中时,它的使用计数器被设置为 1 (由于 put 操作)。对缓存中的键执行 getput 操作,使用计数器的值将会递增。

 

示例:

输入:
["LFUCache", "put", "put", "get", "put", "get", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [3], [4, 4], [1], [3], [4]]
输出:
[null, null, null, 1, null, -1, 3, null, -1, 3, 4]

解释:
// cnt(x) = 键 x 的使用计数
// cache=[] 将显示最后一次使用的顺序(最左边的元素是最近的)
LFUCache lFUCache = new LFUCache(2);
lFUCache.put(1, 1);   // cache=[1,_], cnt(1)=1
lFUCache.put(2, 2);   // cache=[2,1], cnt(2)=1, cnt(1)=1
lFUCache.get(1);      // 返回 1
                      // cache=[1,2], cnt(2)=1, cnt(1)=2
lFUCache.put(3, 3);   // 去除键 2 ,因为 cnt(2)=1 ,使用计数最小
                      // cache=[3,1], cnt(3)=1, cnt(1)=2
lFUCache.get(2);      // 返回 -1(未找到)
lFUCache.get(3);      // 返回 3
                      // cache=[3,1], cnt(3)=2, cnt(1)=2
lFUCache.put(4, 4);   // 去除键 1 ,1 和 3 的 cnt 相同,但 1 最久未使用
                      // cache=[4,3], cnt(4)=1, cnt(3)=2
lFUCache.get(1);      // 返回 -1(未找到)
lFUCache.get(3);      // 返回 3
                      // cache=[3,4], cnt(4)=1, cnt(3)=3
lFUCache.get(4);      // 返回 4
                      // cache=[3,4], cnt(4)=2, cnt(3)=3

 

提示:

 

进阶:你可以为这两种操作设计时间复杂度为 O(1) 的实现吗?

以下错误的选项是?

## aop ### before ```cpp #include using namespace std; ``` ### after ```cpp ``` ## 答案 ```cpp class LFUCache { private: int cap; int size; int minfre; unordered_map> m; unordered_map> hash_fre; unordered_map::iterator> hash_node; public: LFUCache(int capacity) : cap(capacity), size(0) {} int get(int key) { if (m.count(key) == 0) return -1; hash_fre[m[key].second].erase(hash_node[key]); m[key].second++; hash_fre[m[key].second].push_back(key); hash_node[key] = --hash_fre[m[key].second].end(); if (hash_fre[minfre].size() == 0) { minfre++; } return m[key].first; } void put(int key, int value) { if (cap <= 0) return; if (get(key) != -1) { m[key].first = value; return; } if (size >= cap) { m.erase(hash_fre[minfre].front()); hash_node.erase(hash_fre[minfre].front()); hash_fre[minfre].pop_front(); } m[key] = {value, 1}; hash_fre[1].push_back(key); hash_node[key] = hash_fre[1].end(); minfre = 1; if (size < cap) size++; } }; ``` ## 选项 ### A ```cpp class Node { public: int cnt; int time; int key; int val; Node(int cnt, int time, int key, int val) { this->cnt = cnt; this->time = time; this->key = key; this->val = val; } bool operator<(const Node &n) const { if (n.cnt == cnt) return time < n.time; return cnt < n.cnt; } }; class LFUCache { public: int size; int time; unordered_map LFU; set tree; LFUCache(int capacity) { time = 0; size = capacity; } int get(int key) { if (LFU.count(key) == 0) return -1; unordered_map::iterator iter = LFU.find(key); Node now = (*iter).second; tree.erase(now); now.cnt++; now.time = time++; tree.insert(now); (*iter).second = now; return now.val; } void put(int key, int value) { if (LFU.count(key) == 0) { Node newNode = Node(1, time++, key, value); if (size == 0) { if (tree.empty()) return; LFU.erase((*(tree.begin())).key); tree.erase(tree.begin()); } else { size--; } LFU.insert(make_pair(key, newNode)); tree.insert(newNode); } else { unordered_map::iterator iter = LFU.find(key); Node now = (*iter).second; tree.erase(now); now.cnt++; now.time = time++; now.val = value; tree.insert(now); (*iter).second = now; } } }; ``` ### B ```cpp class LFUCache { public: LFUCache(int capacity_) : capacity(capacity_), minfreq(0) { iter_table.clear(); freq_table.clear(); } int get(int key) { if (capacity == 0) return -1; auto it = iter_table.find(key); if (it == iter_table.end()) return -1; list::iterator iter = it->second; int value = iter->value; int freq = iter->freq; Value new_node(key, value, freq + 1); freq_table[freq].erase(iter); if (freq_table[freq].size() == 0) { freq_table.erase(freq); if (minfreq == freq) minfreq += 1; } freq_table[freq + 1].push_front(new_node); iter_table[key] = freq_table[freq + 1].begin(); return new_node.value; } void put(int key, int value) { if (capacity == 0) return; auto it = iter_table.find(key); if (it == iter_table.end()) { if (iter_table.size() == capacity) { auto it2 = freq_table[minfreq].back(); iter_table.erase(it2.key); freq_table[minfreq].pop_back(); if (freq_table[minfreq].size() == 0) { freq_table.erase(minfreq); } } freq_table[1].push_front(Value{key, value, 1}); iter_table[key] = freq_table[1].begin(); minfreq = 1; } else { list::iterator iter = it->second; int freq = iter->freq; Value new_node(iter->key, value, freq + 1); freq_table[iter->freq].erase(iter); if (freq_table[freq].size() == 0) { freq_table.erase(freq); if (minfreq == freq) minfreq += 1; } freq_table[freq + 1].push_front(new_node); iter_table[key] = freq_table[freq + 1].begin(); } } private: struct Value { Value(int key_, int value_, int freq_) : key(key_), value(value_), freq(freq_) {} int key; int value; int freq; }; int capacity; int minfreq; unordered_map::iterator> iter_table; unordered_map> freq_table; }; ``` ### C ```cpp struct Value { Value(int count_, int time_, int key_, int value_) : count(count_), key(key_), value(value_), time(time_) {} bool operator<(const Value &a) const { return count == a.count ? time < a.time : count < a.count; } int key; int value; int count; int time; }; class LFUCache { public: LFUCache(int capacity_) : capacity(capacity_), time(0) {} int get(int key) { if (capacity == 0) return -1; auto it = table.find(key); if (it == table.end()) return -1; Value cache = it->second; judge.erase(cache); cache.count++; cache.time = ++time; judge.insert(cache); it->second = cache; return cache.value; } void put(int key, int value) { if (capacity == 0) return; auto it = table.find(key); if (it == table.end()) { if (table.size() == capacity) { table.erase(judge.begin()->key); judge.erase(judge.begin()); } Value put_(0, ++time, key, value); table.insert({key, put_}); judge.insert(put_); } else { Value temp = it->second; judge.erase(temp); Value put_(++temp.count, ++time, key, value); it->second = put_; judge.insert(put_); } } private: const int capacity; int time; unordered_map table; set judge; }; ```