leetcode 460
方法一:双哈希表法
题目要求需要在常数时间完成插入和查找算法,联系之前的LRU算法,很容易想到用哈希表。具体做法如下:
第一个哈希表存储 使用频率freq 和一个双向链表这样一对映射,链表的每个节点存储key value
和freq
(使用频率);
第二个哈希表存储 freq和链表中的一个节点这样一对映射;
1.对于get()
操作
首先根据key找到对应的链表节点,从而在第二个哈希表中找到value,freq,
同时将该节点从当前链表删除(如果删除后为空,可能需要更新最小freq).将freq+1,新建一个节点插入下一个链表中;
2.对于put()
操作
如果key
已经存在,那么等同于get()操作,只需要另外将value更新就可以;
否则,判断当前是否达到了最大容量限制,若没有则只需要新建一个节点{freq=1,key,value}
,更新两个哈希表和最小使用频率即可;若达到了最大最大容量,找到最小使用频率对应的节点,将其从两个哈希表中删除,同时可能需要更新最小使用频率;
class LFUCache {
public:
struct node
{
int key,val,freq;
node(int k,int v,int f):key(k),val(v),freq(f){}
};
unordered_map<int,list<node>>cache;//以频率为索引
unordered_map<int,list<node>::iterator>sea;//以键值为索引
int sz;
int minfreq;
public:
LFUCache(int capacity) {
sz=capacity;
minfreq=0;
}
int get(int key) {
if(sz==0||sea.find(key)==sea.end())return -1;
auto it=sea[key];
list<node>::iterator no=it;
int f=no->freq,val=no->val;
cache[f].erase(no);
node n(key,val,f+1);
cache[f+1].push_front(n);
if(cache[f].size()==0)
{
cache.erase(f);
if(minfreq==f)
minfreq++;
}
sea[key]=cache[f+1].begin();
return val;
}
void put(int key, int value) {
if(sz==0)return;
if(sea.size()>0&&sea.find(key)!=sea.end())
{
get(key);
sea[key]->val=value;
}
else
{
if(sea.size()==sz)
{
auto no=cache[minfreq].back();
int f=no.freq,val=no.val,k=no.key;
cache[minfreq].pop_back();
if(cache.count(minfreq)==0)
{
minfreq+=1;
cache.erase(f);
}
sea.erase(k);
}
auto no=node(key,value,1);
cache[1].push_front(no);
minfreq=1;
sea[key]=cache[1].begin();
}
}
};