# LFU 缓存
请你为 最不经常使用(LFU)缓存算法设计并实现数据结构。
实现 LFUCache
类:
LFUCache(int capacity)
- 用数据结构的容量 capacity
初始化对象
int get(int key)
- 如果键存在于缓存中,则获取键的值,否则返回 -1。
void put(int key, int value)
- 如果键已存在,则变更其值;如果键不存在,请插入键值对。当缓存达到其容量时,则应该在插入新项之前,使最不经常使用的项无效。在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,应该去除 最近最久未使用 的键。
注意「项的使用次数」就是自插入该项以来对其调用 get
和 put
函数的次数之和。使用次数会在对应项被移除后置为 0 。
为了确定最不常使用的键,可以为缓存中的每个键维护一个 使用计数器 。使用计数最小的键是最久未使用的键。
当一个键首次插入到缓存中时,它的使用计数器被设置为 1
(由于 put 操作)。对缓存中的键执行 get
或 put
操作,使用计数器的值将会递增。
示例:
输入:
["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
提示:
0 <= capacity, key, value <= 104
- 最多调用
105
次 get
和 put
方法
进阶:你可以为这两种操作设计时间复杂度为 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;
};
```