Leetcode刷题笔记-146.LRU缓存机制
算法思想
链接: https://leetcode-cn.com/problems/lru-cache/.
题目中给予了两个函数,get和put函数,并且要求时间复杂度为O(1)。
put约束条件如下:
(1)关键字存在:变更数据。
(2)关键字不存在:判断缓存容量是否达到上限:达到了上限,则应该删除最久未使用的数据;未达上限,直接添加。
get约束条件如下:
如果关键字在缓存,获取该关键字的值,否则返回-1。
此题目要求的数据结构需要满足:查找快、插入、删除快且有顺序之分的特点。
-
查找快且时间复杂度为O(1),我们可以想到哈希表这种数据结构(可以看成“数组+链表 ”,类似c语言中“指针数组”)。具有查找快特点。
-
有顺序之分(用于区分最近使用和最久未使用的数据)、插入快、删除快我们可以想到链表这种数据结构。
于是结合两个数据结构我们可以得到一种新的数据结构:哈希链表。此题用这种数据结构就可解决。
代码
class LRUCache {
private:
int cap;
list<pair<int,int>> _list; //声明一个由键值对组成的双向链表list
unordered_map<int,list<pair<int,int>>::iterator> map; //hash表,map相当于数组+链表
public:
LRUCache(int capacity) {
this->cap=capacity;
}
int get(int key) {
auto it=map.find(key); //指向list的指针
if(it==map.end()) return -1; //查到结尾没查到
// key 存在,把 (k, v) 换到队头
pair<int,int> kv=*map[key]; //创建list节点,map[key]即指向list结点的指针
_list.erase(map[key]); //删除节点
_list.push_front(kv); //插入节点
// 更新 (key, value) 在 list 中的位置
map[key]=_list.begin();
return kv.second;
}
void put(int key, int value) {
/* 要先判断 key 是否已经存在 */
auto it=map.find(key);
if(it==map.end()){
/* key 不存在,判断 list 是否已满 */
if(_list.size()==cap){
// list 已满,删除尾部的键值对位置
// list 和 map 中的数据都要删除
auto lastPair =_list.back(); //指向链表尾部节点
int lastKey=lastPair.first; //取出key值
map.erase(lastKey);
_list.pop_back();
}
// list 没满,可以直接添加
_list.push_front(make_pair(key,value)); //创建一个对组
map[key]=_list.begin();
}
else{
/* key 存在,更改 value 并换到队头 */
_list.erase(map[key]);
_list.push_front(make_pair(key,value));
map[key]=_list.begin();
}
}
};
代码原作者:labuladong
转载链接: https://leetcode-cn.com/problems/lru-cache/solution/lru-ce-lue-xiang-jie-he-shi-xian-by-labuladong/