Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the following operations: get and put.
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(key, value) - Set or insert the value if the key is not already present. When the cache reaches its capacity, it should invalidate the least frequently used item before inserting a new item. For the purpose of this problem, when there is a tie (i.e., two or more keys that have the same frequency), the least recently used key would be evicted.
Follow up:
Could you do both operations in O(1) time complexity?
Example:
1 2 3 4 5 6 7 8 9 10 11 12
LFUCache cache = new LFUCache( 2 /* capacity */ );
using NodeListNode = pair<int, list<pair<int, int>>>;
classLFUCache { int _c; unordered_map<int, list<pair<int, int>>::iterator> _m; list<NodeListNode> _q; unordered_map<int, list<NodeListNode>::iterator> refCount; public: LFUCache(int capacity) { _c = capacity; } intget(int key){ if (!_m.count(key)) return-1; increaseCount(key); auto iter = _m[key]; return iter->second; } voidput(int key, int value){ if (_c <= 0) return; if (_m.count(key)) { auto iter = _m[key]; iter->second = value; } else { if (_m.size() >= _c) { evict(); } list<pair<int, int>>::iterator nextKeyIter; if (_q.empty() || _q.front().first > 1) { _q.emplace_front(1, list<pair<int, int>>()); nextKeyIter = _q.front().second.insert(_q.front().second.end(), make_pair(key, value)); } else { nextKeyIter = _q.front().second.insert(_q.front().second.end(), make_pair(key, value)); } _m[key] = nextKeyIter; } increaseCount(key); } voidincreaseCount(int key){ if (!refCount.count(key)) { refCount[key] = _q.begin(); return; } auto iter = refCount[key]; int currCnt = iter->first; int nextCnt = currCnt + 1; auto nextIter = iter; nextIter++; if (nextIter == _q.end() || (nextIter)->first != nextCnt) { nextIter = _q.insert(nextIter, NodeListNode(nextCnt, list<pair<int, int>>())); } int value = _m[key]->second; auto nextKeyIter = nextIter->second.insert(nextIter->second.end(), make_pair(key, value)); iter->second.erase(_m[key]); if (iter->second.empty()) { _q.erase(iter); } _m[key] = nextKeyIter; refCount[key] = nextIter; } voidevict(){ if (_q.empty()) return; int key = _q.front().second.front().first; _q.front().second.pop_front(); _m.erase(key); refCount.erase(key); } };
/** * 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); */