题目描述
设计一个数据结构,实现LRU Cache的功能(Least Recently Used – 最近最少使用缓存)。它支持如下2个操作: get 和 put。
int get(int key) – 如果key已存在,则返回key对应的值value(始终大于0);如果key不存在,则返回-1。
void put(int key, int value) – 如果key不存在,将value插入;如果key已存在,则使用value替换原先已经存在的值。如果容量达到了限制,LRU Cache需要在插入新元素之前,将最近最少使用的元素删除。
请特别注意“使用”的定义:新插入或获取key视为被使用一次;而将已经存在的值替换更新,不算被使用。
限制:请在O(1)的时间复杂度内完成上述2个操作。
输入描述
第一行读入一个整数n,表示LRU Cache的容量限制。 从第二行开始一直到文件末尾,每1行代表1个操作。
如果每行的第1个字符是p,则该字符后面会跟随2个整数,表示put操作的key和value。
如果每行的第1个字符是g,则该字符后面会跟随1个整数,表示get操作的key。
输出描述
按照输入中get操作出现的顺序,按行输出get操作的返回结果。
示例
输入
2
p 1 1
p 2 2
g 1
p 2 102
p 3 3
g 1
g 2
g 3
输出
1
1
-1
3
说明
2 //Cache容量为2
p 1 1 //put(1, 1)
p 2 2 //put(2, 2)
g 1 //get(1), 返回1
p 2 102 //put(2, 102),更新已存在的key,不算被使用
p 3 3 //put(3, 3),容量超过限制,将最近最少使用的key=2清除
g 1 //get(1), 返回1
g 2 //get(2), 返回-1
g 3 //get(3), 返回3
题目分析
这道题可以采用(hashMap + 双向链表)的思想完成。
其中双向链表的插入复杂度为O(1), hashMap的查找复杂度也为O(1).符合题目的要求。
思路:
put操作:
首先查看在map中是否出现了key值,如果出现了key则替换掉value
如果没出现的话,考虑链表是否满,如果没有满的话,直接在双向链表最前端插入。
如果满的话,删除双向链表最后端的数元素后再插入。同时更新map。
get操作:
- 如果map出现了key值,则返回相应的value,同时将链表中的对应的key - value提升到队列首部,更新map。
- 如果没出现则返回 - 1
使用hashmap存放的原因是hashmap存放的value为双向列表的迭代器(元素的指针),这样可以使得我们在列表中查询元素的时间复杂度从O(N)下降到O(1)。
详情请看代码注释:
代码
C++代码如下:
#include <iostream>
#include <unordered_map>
#include <list>
#include <utility>
using namespace std;
typedef unordered_map<int, list<pair<int, int> >::iterator> hashMap;
//用哈希表进行快速查找,内部元素是一种完全无序的状态
list<pair<int, int> > li;
hashMap map;
int capacity;
void put(int k,int v)
{
auto it=map.find(k);//找到k对应的指针
if(it!=map.end())
{
it->second->second=v;//如果没有满则直接插入
}
else
{
if(li.size()==capacity)
{
int key=li.back().first;//获取链表尾部的key值
li.pop_back();//弹出尾部元素
map.erase(key);//删除key指针
}
li.push_front(make_pair(k,v));//将新的key,value插入到链表中
map[k]=li.begin();//map存放链表最前端的指针
}
}
int get(int k)
{
auto it=map.find(k);//找到k对应的链表指针
if(it==map.end())
return -1;//没有找到元素
int res=it->second->second;//获取key对应的value值
li.erase(it->second);//将value从链表中删除
li.push_front(make_pair(k,res));//将使用过的key,value放在链表的最前端
map[k]=li.begin();//map存放链表最前端的指针
return res;
}
int main()
{
int k,v;
char c;
cin>>capacity;
while(cin>>c)
{
if(c=='p')
{
cin>>k>>v;
if(capacity<=0)//当没有元素时,无法使用LRU,所以直接退出
continue;
put(k,v);
}
if(c=='g')
{
cin>>k;
cout<<get(k)<<endl;
}
}
return 0;
}