LRU Cache——携程2019届秋招专业笔试(研发方向)

题目描述

设计一个数据结构,实现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操作:

  1. 如果map出现了key值,则返回相应的value,同时将链表中的对应的key - value提升到队列首部,更新map。
  2. 如果没出现则返回 - 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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值