此题有两个需要注意的点,最近-最少未使用。
比如说我们有几个键值对,那么,如果要淘汰一个的话按照题意“存在相同使用频率应该去除最近最久未使用的”,应当先比较计数器,不相等淘汰计数器最少的;若计数器相等,那么淘汰最晚加入的。
我们在类内部维护一个时间戳,只要进入一个操作内,时间戳就+1来维护时间序列。
剩下的是就是节点的更新工作,在本题刚开始时,准备使用堆来维护节点,以哈希表来维护键,但事实实际上用树状结构足够了,因为维护的代价都是log(n)。需要注意的就是节点的先删除再插入,在这个过程中,更新计数器、时间戳即可。
这里采用C++来编写。
#include <unordered_map>
#include <set>
struct Node{
public:
int timestamp;
int cnt;
int key;
int val;
Node()= default;
Node(int _key,int _val,int _timestamp,int _cnt):
key(_key),val(_val),cnt(_cnt),timestamp(_timestamp){}
bool operator<(const Node& other)const{
if(cnt==other.cnt){
return timestamp<other.timestamp;
}
return cnt<other.cnt;
}
};
class LFUCache {
int capacity;
int timestamp;
std::set<Node> node_set;
std::unordered_map<int,Node> nodes;
public:
LFUCache(int _capacity) {
capacity=_capacity;
timestamp=0;
}
int get(int key) {
if(capacity<=0){
return -1;
}
timestamp++;
auto it=nodes.find(key);
if(it==nodes.end()){
return -1;
}
Node n=it->second;
node_set.erase(n);
n.cnt++;
n.timestamp=timestamp;
nodes[n.key]=n;
node_set.insert(n);
return n.val;
}
void put(int key, int value) {
if(capacity<=0){
return ;
}
timestamp++;
auto it=nodes.find(key);
if(it!=nodes.end()){
Node n=it->second;
node_set.erase(n);
n.timestamp=timestamp;
n.cnt++;
n.val=value;
node_set.insert(n);
nodes[key]=n;
}
else{
if(node_set.size()==capacity){
auto first=node_set.begin();
int k=first->key;
node_set.erase(*first);
nodes.erase(k);
}
Node node(key,value,timestamp,1);
nodes[key]=node;
node_set.insert(node);
}
}
};