题目描述
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get
和 写入数据 put
。
获取数据 get(key)
- 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value)
- 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。
进阶:
你是否可以在 O(1) 时间复杂度内完成这两种操作?
示例:
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
解题思路
用一个链表记录当前缓存中所有的键值对,并且每次新来的访问都对链表进行重新调整,把最近访问的键值对放到链表头部。然后为了快速访问缓存中的值,维护一个map,key是实际数据的key,对应的value指向该key在链表中的位置节点,这样每次添加键值对时,先判断map中是否有该key,若有则修改链表中对应节点的value;若没有则把该键值对添加到链表头部,去除链表尾部超过规定长度的节点,并在map中添加key以及对应的链表节点指针。
代码
1 class LRUCache { 2 public: 3 LRUCache(int capacity) { 4 size = capacity; 5 } 6 7 int get(int key) { 8 auto it = hash.find(key); 9 if(it == hash.end()) return -1; 10 cache.splice(cache.begin(), cache, it->second); 11 return it->second->second; 12 } 13 14 void put(int key, int value) { 15 auto it = hash.find(key); 16 if(it != hash.end()){ 17 it->second->second = value; 18 return cache.splice(cache.begin(), cache, it->second); 19 } 20 cache.insert(cache.begin(), make_pair(key, value)); 21 hash[key] = cache.begin(); 22 if(cache.size() > size){ 23 hash.erase(cache.back().first); 24 cache.pop_back(); 25 } 26 } 27 private: 28 unordered_map<int, list<pair<int, int>>::iterator> hash; 29 list<pair<int, int>> cache; 30 int size; 31 }; 32 33 /** 34 * Your LRUCache object will be instantiated and called as such: 35 * LRUCache obj = new LRUCache(capacity); 36 * int param_1 = obj.get(key); 37 * obj.put(key,value); 38 */