Description
设计和实现一个LRU(最近最少使用)缓存数据结构,使它应该支持以下操作: get
和 put
。
get(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); // 该操作,会将 key 2 作废
cache.get(2); // 返回 -1 (结果不存在)
cache.put(4, 4); // 该操作,会将 key 1 作废
cache.get(1); // 返回 -1 (结果不存在)
cache.get(3); // 返回 3
cache.get(4); // 返回 4
Solution
思路
list<pair<int, int>>
(key, value)存在list中。unordered_map<int, list<pair<int, int>>::iterator>
存储key和key所在的list的位置。- 链表头是最近使用过的元素。每当执行
put(key, value)
或get(key)
操作,把(key, value)
插入链表头。 - 链表尾是最久未读过的元素,当超过存储上限时,首先删掉链表尾和map对应的元素。
易错点
get(key)
操作也会让链表中的key放到链表头。put(key, value)
,若map中本来就存了key,则应替换成新的value,链表中的(key, value)放到链表头;而不应该删除链表尾的元素及其在map中的值。
代码
Leetcode accepted
class LRUCache {
private:
int cap;
int count;
unordered_map<int, list<pair<int, int>>::iterator> m;
list<pair<int, int>> queue;
public:
LRUCache(int capacity) {
cap = capacity;
count = 0;
}
int get(int key) {
int res = -1;
auto p = m.find(key);
if (p != m.end()) {
res = p->second->second;
queue.erase(p->second);
queue.push_front(make_pair(key, res));
p->second = queue.begin();
}
return res;
}
void put(int key, int value) {
auto p = m.find(key);
if (p != m.end()) {
queue.erase(p->second);
}
else if (count == cap) {
int delkey = queue.back().first;
queue.pop_back();
m.erase(delkey);
}
else {
++count;
}
queue.push_front(make_pair(key, value));
m[key] = queue.begin();
}
};