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();
}
}
};