146. LRU Cache
Design and implement a data structure for Least Recently Used (LRU) 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 reached its capacity, it should invalidate the least recently used item before inserting a new item.
Follow up:
Could you do both operations in O(1) time complexity?
Example:
LRUCache cache = new LRUCache( 2 /* capacity */ ); cache.put(1, 1); cache.put(2, 2); cache.get(1); // returns 1 cache.put(3, 3); // evicts key 2 cache.get(2); // returns -1 (not found) cache.put(4, 4); // evicts key 1 cache.get(1); // returns -1 (not found) cache.get(3); // returns 3 cache.get(4); // returns 4
解题思路:缓存的实现。map<key,<value,time>>大致是这样的数据结构,即把每个键对应到一个结构体(记录值和访问时间).
本题要求存取时间均为O(1),很容易想到hash,而当存取某个已经存在的值的时候需要把该节点放在端点处,所以需要用链表来实现。
综上,用一个list来记录当前缓存中的值,而且list是按照时间访问先后次序逆序存放着,即先访问的放在list尾部,后访问的放在list首部,
这样每次put的时候先看键是否存在,已经存在的话把它放到list首部即可,否则看是否list已满,若已满则需要弹出最后的元素,否则直接放在list首部。
class LRUCache { public: LRUCache(int capacity) { _capacity=capacity; } int get(int key) { auto it=cache.find(key); if(it==cache.end())return -1; touch(it); return it->second.first; } void put(int key, int value) { auto it=cache.find(key); if(it!=cache.end())touch(it); else { if(used.size()==_capacity){ cache.erase(used.back()); used.pop_back(); } used.emplace_front(key); } cache[key]={value, used.begin()}; } private: typedef list<int> LI; typedef pair<int, LI::iterator> PII; typedef unordered_map<int, PII>HIPII; int _capacity; HIPII cache; LI used; void touch(HIPII::iterator it){ int key=it->first; used.erase(it->second.second); used.emplace_front(key); it->second.second=used.begin(); } }; /** * Your LRUCache object will be instantiated and called as such: * LRUCache obj = new LRUCache(capacity); * int param_1 = obj.get(key); * obj.put(key,value); */