LRU:Least Recently used
操作系统课上讲过。整体是用一个栈,新使用的就抽出来放到栈顶端。如果栈大小达到限制那么删除栈底。
当然这样时间复杂度太高,查找时间O(n),更新时间O(n)。
如果上面的两个操作时间复杂度要达到O(1)的话。思考:查找O(1),也就是有一个key,O(1)时间要查找是否存在,肯定哈希表逃不了了。
另外还要按时间排序,最近使用的在前面,最早使用过的在后面。但每次查找到的节点可能在中间,所以需要动态的插入删除,也就是链表。
那么整体来说:
一个链表存储key-value。并且按照出现时间从最近到最早排列(最近出现的位于链表头部)。
另外还有一个哈希表,key就是链表节点的key,value是对应该key的链表节点项(指针or迭代器)。
这样通过哈希表可以O(1)时间定位对应链表节点。并且更新时,直接把该节点移动到链表头端,并更新哈希表映射关系。这个操作也是O(1)。
题目:
设计和构建一个“最近最少使用”缓存,该缓存会删除最近最少使用的项目。缓存应该从键映射到值(允许你插入和检索特定键对应的值),并在初始化时指定最大容量。当缓存被填满时,它应该删除最近最少使用的项目。
它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。
示例:
LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得密钥 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得密钥 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4
解答:
class LRUCache { public: unordered_map<int,list<pair<int,int> >::iterator> mp; list<pair<int,int> >data; int n; LRUCache(int capacity) { n=capacity; } int get(int key) { if(mp.count(key)){ put(key,mp[key]->second); return mp[key]->second; } return -1; } void put(int key, int value) { if(mp.count(key)){ auto iter=mp[key]; data.push_front({key,value});//更新到链表头部 data.erase(iter);//删除之前的迭代器 mp[key]=data.begin(); } else{ if(data.size()>=n){ auto p=data.back(); mp.erase(p.first); data.pop_back(); } data.push_front({key,value}); mp[key]=data.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); */