LRU缓存
- 题解1 双map(差2个testcases)
- 题解2 哈希表+双向链表(参考)
- 题解3 STL:list+unordered_map
请你设计并实现一个满足
LRU
(最近最少使用) 缓存 约束的数据结构。
实现
LRUCache
类:
LRUCache(int capacity)
以 正整数 作为容量
capacity
初始化
LRU
缓存
int get(int key)
如果关键字
key
存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value)
如果关键字 key 已经存在,则变更其数据值
value
;如果不存在,则向缓存中插入该组
key-value
。如果插入操作导致关键字数量超过
capacity
,则应该 逐出 最久未使用的关键字。
函数
get
和
put
必须以 O(1) 的平均时间复杂度运行。
提示:
- 1 <=
capacity
<= 3000 - 0 <=
key
<= 10000 - 0 <=
value
<= 105 - 最多调用
2
∗
1
0
5
2 * 10^5
2∗105 次
get
和put
题解1 双map(差2个testcases)
class LRUCache {
int LRUcapacity;
map<int, int> cacheMap;
map<int, int> usecases;
int time = 0;
static bool cmp(const pair<int, int>& lhs, const pair<int, int>& rhs) {
return lhs.second < rhs.second;
}
public:
LRUCache(int capacity) {
LRUcapacity = capacity;
}
int get(int key) {
if(cacheMap.count(key)){
// 记录访问时刻(value越大代表最近使用)
usecases[key] = time++;
return cacheMap[key];
}
else return -1;
}
void put(int key, int value) {
if(cacheMap.count(key)){
cacheMap[key] = value;
usecases[key] = time++;
}else{
// 没满足O(1)的时间复杂度
if(cacheMap.size() + 1 > LRUcapacity){
// 拿到最早访问的关键字 value最小
vector<pair<int, int>> usecasesVector(usecases.begin(), usecases.end());
sort(usecasesVector.begin(), usecasesVector.end(), cmp);
int idx = usecasesVector[0].first;
cacheMap.erase(cacheMap.find(idx));
usecases.erase(usecases.find(idx));
}
cacheMap[key] = value;
usecases[key] = time++;
}
}
};
/**
* 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);
*/
题解2 哈希表+双向链表(参考)
class LRUCache {
int LRUcapacity;
// 双向链表保证每次找最近使用的操作时间复杂度为O(1)
struct Node{
int key;
int value;
Node* prev;
Node* next;
Node(): key(0), value(0), prev(nullptr), next(nullptr){}
Node(int key1, int value1): key(key1), value(value1), prev(nullptr), next(nullptr){}
};
map<int, Node*> cacheMap;
Node* head, *tail;
public:
LRUCache(int capacity) {
LRUcapacity = capacity;
head = new Node();
tail = new Node();
head->next = tail;
tail->prev = head;
}
int get(int key) {
if(cacheMap.count(key)){
// 把node添加到头结点H
// 对于双向链表, 原位置node需要修正的:
// node->next->prev 和 node->prev->next
// 目标位置H需要修正的:
// H->next, H->next->prev
Node* getNode = cacheMap[key];
getNode->prev->next = getNode->next;
getNode->next->prev = getNode->prev;
getNode->prev = head;
getNode->next = head->next;
head->next = head->next->prev = getNode;
return getNode->value;
}
else return -1;
}
void put(int key, int value) {
if(cacheMap.count(key)){
Node* getNode = cacheMap[key];
getNode->value = value;
// 添加到头结点
getNode->prev->next = getNode->next;
getNode->next->prev = getNode->prev;
getNode->prev = head;
getNode->next = head->next;
head->next = head->next->prev = getNode;
}else{
if(cacheMap.size() + 1 > LRUcapacity){
Node* pre = tail->prev;
cacheMap.erase(cacheMap.find(pre->key));
pre->prev->next = pre->next;
pre->next->prev = pre->prev;
// 防止内存泄漏
delete pre;
}
cacheMap[key] = new Node(key, value);
Node* getNode = cacheMap[key];
// 新结点添加到头结点 (代表最近被使用)
// 新结点无原位置,所以只需要修改H附近的链
getNode->prev = head;
getNode->next = head->next;
head->next = head->next->prev = getNode;
}
}
};
题解3 STL:list+unordered_map
class LRUCache {
const int cap;
list<pair<int, int>> cache;
unordered_map<int, decltype(cache.begin())> dict;
public:
LRUCache(int capacity) : cap(capacity) {}
int get(int key) {
if (!dict.count(key))
return -1;
cache.splice(cache.cend(), cache, dict[key]);
return dict[key]->second;
}
void put(int key, int value) {
if (!dict.count(key)) {
if (cache.size() == cap) {
dict.erase(cache.front().first);
cache.pop_front();
}
dict[key] = cache.emplace(cache.cend(), key, value);
}
else {
dict[key]->second = value;
cache.splice(cache.cend(), cache, dict[key]);
}
}
};