LeetCode 460. LFU Cache
Hashtable + BST
用hashtable保存key->Node,另外用一个set<Node>来根据freq和time进行排序,保证容量满时删除的是LFU的节点。
注意这里hashtable的value存的是Node,不是指针也不是set的iterator。因为用指针只能做到从set里删除O(1),而set的插入还是O(logn)的,总的时间复杂度O(logn)。
struct Node{ int key; int value; int freq; int time; bool operator<(const Node &node) const{ if (freq!=node.freq) return freq<node.freq; return time<node.time; // least recently used first } }; class LFUCache { private: int cap; int timestamp; unordered_map<int,Node> m; // key -> node set<Node> s; void update(Node &node){ s.erase(node); // log(n) ++node.freq; node.time = timestamp++; s.insert(node); // log(n) } public: LFUCache(int capacity) { cap = capacity; timestamp = 0; } int get(int key) { if (!m.count(key)) return -1; int res=m[key].value; update(m[key]); return res; return 0; } void put(int key, int value) { if (cap==0) return; if (m.count(key)){ m[key].value = value; update(m[key]); return; } if (m.size()==cap){ // need to evict Node node=*s.begin(); m.erase(node.key); s.erase(node); } Node newNode{key,value,1,timestamp++}; m[key] = newNode; s.insert(newNode); } }; /** * Your LFUCache object will be instantiated and called as such: * LFUCache* obj = new LFUCache(capacity); * int param_1 = obj->get(key); * obj->put(key,value); */
时间复杂度 O(logn)
Hashtable + Linked List
这里思路就和LRU类似,用一个hashtable存放list的iterator。由于LFU要考虑frequency,我们建立 freq 到 list of keys with this freq 的映射,同时维护min_freq,并保证每个list都是最近访问的放在前面。
这样的好处是,如果我们要更新一个节点的freq,我们可以直接通过iterator在对应freq的list里找到并删除,并插入++freq对应list的最前面。
struct Node{ int key; int value; int freq; list<int>::iterator it; }; class LFUCache { private: int cap; int min_freq; unordered_map<int,Node> m; // key -> node unordered_map<int,list<int>> l; // freq -> keys with freq void update(Node &node){ int prev_freq=node.freq; int freq=++(node.freq); l[prev_freq].erase(node.it); if (l[prev_freq].empty() && min_freq==prev_freq){ // update min_freq l.erase(prev_freq); ++min_freq; } l[freq].push_front(node.key); node.it = l[freq].begin(); } public: LFUCache(int capacity) { cap = capacity; min_freq = 0; } int get(int key) { if (!m.count(key)) return -1; int res=m[key].value; update(m[key]); return res; } void put(int key, int value) { if (cap==0) return; if (m.count(key)){ m[key].value = value; update(m[key]); return; } if (m.size()==cap){ // need to evict m.erase(l[min_freq].back()); l[min_freq].pop_back(); } min_freq = 1; l[1].push_front(key); m[key] = {key,value,1,l[1].begin()}; } }; /** * Your LFUCache object will be instantiated and called as such: * LFUCache* obj = new LFUCache(capacity); * int param_1 = obj->get(key); * obj->put(key,value); */
时间复杂度 O(1)