Problem:
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
Solution:
笔试高频题,我在今年笔试中已经两次碰见该题了。这道题是链表和哈希表的结合。对于这道题有几个基础知识必须了解,一个是链表的迭代器失效问题,和vector不同,链表的删除操作只会使迭代器指向的当前节点失效。第二个是第十行的splice函数,它的原型是void splice (iterator position, list& x, iterator i),其作用是仅将链表x中的i指向的一个节点拼接到position的位置。接下来就很简单了,put函数通过哈希表找到key所在链表中的迭代器,将其删除,然后在链表开头添加新的pair,并将哈希表重新赋值。如果超出限制范围,则在链表和哈希表中删除最后一个节点。对于get函数,通过哈希表找到结果,然后通过splice函数将该节点移动到链表开头。
Code:
1 class LRUCache { 2 public: 3 LRUCache(int capacity) { 4 limit = capacity; 5 } 6 7 int get(int key) { 8 auto it = um.find(key); 9 if (it == um.end()) return -1; 10 l.splice(l.begin(), l, it->second); 11 return it->second->second; 12 } 13 14 void put(int key, int value) { 15 auto iter = um.find(key); 16 if(iter != um.end()) 17 l.erase(iter->second); 18 l.push_front(make_pair(key,value)); 19 um[key] = l.begin(); 20 if(um.size() > limit){ 21 um.erase(l.rbegin()->first); 22 l.pop_back(); 23 } 24 } 25 private: 26 int limit; 27 list<pair<int, int>> l; 28 unordered_map<int, list<pair<int, int>>::iterator> um; 29 }; 30 31 /** 32 * Your LRUCache object will be instantiated and called as such: 33 * LRUCache obj = new LRUCache(capacity); 34 * int param_1 = obj.get(key); 35 * obj.put(key,value); 36 */