Leetcode 460. LFU 缓存机制(困难)
题目:
get(key)
方法会去缓存中查询键 key
,如果 key
存在,则返回 key
对应的 val
,否则返回 -1。
put(key, value)
方法插入或修改缓存。如果 key
已存在,则将它对应的值改为 val
;如果 key
不存在,则插入键值对 (key, val)
。
当缓存达到容量 capacity
时,则应该在插入新的键值对之前,删除使用频次(后文用 freq
表示)最低的键值对。如果 freq
最低的键值对有多个,则删除其中最旧的那个。
思路:
map<key,node> kv保存node
map<freq,list<node>> fv保存freq对应的node双向链表,按照头部最旧、尾部最新排列
minFreq记录当前所有key的最小Freq
node记录key、val、freq
1、当get时,如果存在,先拿到node,然后对node进行update,将其freq+1,同时从oldFreq的list删除,并添加到newFreq的list中。此时如果minFreq==oldFreq&&fv[minFreq].empty,证明minFreq的node已经没有,minFreq+1
2、当put时
- 如果capacity为0,则什么都不做
- 如果key存在,更新node值,并update(node)
- 如果kv.size==capacity,removeMinFreqKey。也就是从minFreq对应的list中移除front,并从kv中移除
- 添加k v,minFreq=1
struct Node{ int key; int val; int freq; Node* pre; Node* next; Node(int k,int v){ key=k; val=v; freq=1; pre=nullptr; next=nullptr; } }; class DoubleList { public: DoubleList(){ length=0; head=new Node(0,0); tail=new Node(0,0); head->next=tail; tail->pre=head; } void addLast(Node* node){ tail->pre->next=node; node->pre=tail->pre; node->next=tail; tail->pre=node; length++; } Node* delFront(){ Node* node=head->next; head->next=node->next; node->next->pre=head; length--; return node; } void delNode(Node* node){ Node* pre=node->pre; Node* next=node->next; pre->next=next; next->pre=pre; length--; } bool empty(){ return length==0; } private: int length; Node* head; Node* tail; }; class LFUCache { public: LFUCache(int capacity) { this->capacity=capacity; minFreq=0; } int get(int key) { unordered_map<int, Node*>::iterator it=kv.find(key); if(it==kv.end()) { return -1; } Node* node=it->second; // 增加 key 对应的 freq increaseFreq(node); int val=node->val; return val; } void put(int key, int value) { // 如果容量为0,则什么都不做 if(capacity<=0){ return; } /* 若 key 已存在,修改对应的 val 即可 */ if(kv.count(key)==1){ Node* node=kv[key]; // 增加 key 对应的 freq increaseFreq(node); node->val=value; return; } /* key 不存在,需要插入 */ /* 容量已满的话需要淘汰一个 freq 最小的 key */ if(kv.size()==capacity){ removeMinFreq(); } // 添加新 key val addKey(key,value); // 插入新 key 后最小的 freq 肯定是 1 minFreq=1; } private: // 增加node的freq void increaseFreq(Node* node){ int oldFreq=node->freq; // 更新node自身的freq node->freq++; // 从oldfreq对应的list中删除node fv[oldFreq].delNode(node); // 在新freq对应的list中添加node fv[oldFreq+1].addLast(node); // 如果oldFreq==1且对应node为空,则minFreq+1 if(oldFreq==minFreq&&fv[oldFreq].empty()){ minFreq++; } } // 除去freq最小最旧的node void removeMinFreq(){ Node* node=fv[minFreq].delFront(); kv.erase(node->key); // 因为此时后边跟着的操作是addKey,所以minFreq肯定为1 } //添加key void addKey(int key, int val){ Node* node=new Node(key,val); kv.insert(make_pair(key,node)); fv[1].addLast(node); } private: int capacity; // key->node unordered_map<int, Node*> kv; // freq -> list<node> unordered_map<int, DoubleList> fv; int minFreq; };
联系方式:emhhbmdfbGlhbmcxOTkxQDEyNi5jb20=