一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情。
前言
每天一道算法题,死磕算法
题目
请你设计并实现一个满足 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)的平均时间复杂度运行。
示例
输入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]
解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1); // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4
分析
首先我们要理解什么是LRU?
LRU(least recently used)最近最少使用策略,是一种缓存淘汰策略,要注意淘汰这两个字。无论是电脑,手机,浏览器,都有一个缓存空间,但是缓存空间是有限的。当缓存空间满了的时候我们就要清楚哪些无用的缓存,保留有用的缓存。所以关键点是弄清楚什么是无用的缓存,什么是有用的缓存?
我们可以把缓存空间想象成一个队列,最近访问的放到队头,最少使用的放到队尾。
什么是有用的缓存?
LRU里面的recently就说明了什么是有用缓存,就是最近访问的数据。我们会依然保存到缓存中,并把他提升到队列的头部。
什么是无用的缓存?
LRU里面的least就说明了什么是无用缓存,就是最少访问的数据,当有新的缓存进来的时候,我们就把最少访问的数据踢出去。
用什么数据结构来保存cache数据最好?
题目中给的提示是
函数
get和put必须以O(1)的平均时间复杂度运行。
我们来分析一下什么数据结构满足这样的条件
- get为O(1)证明这个数据结构要有时序性,不能无序存储,比如
object就不能满足有序存储的条件,object如果传入是先数字后字符串,没有时序,所以可以使用map - put为O(1)就是插入速度和删除速度为O(1),我们可以使用
map根据key值快速的进行插入和删除,所以这个条件map也是满足的
get(key:number)函数步骤
- 如果cache中有key这个值
- 那么把key所对应的value值返回
- 删除key这条数据,重新添加
- 如果cache中没有key这个值
- 返回-1
put(key:number,value:number)函数步骤
- 如果cache中有这个值
- 删除掉,重新添加
- 如果cache中没有这个值
- 重新添加
- 如果超出了capacity容量
- 删除队尾的值
题解
class LRUCache {
public capacity:number;
public map:Map<any,any>;
constructor(capacity: number) {
this.capacity = capacity;
this.map = new Map();
}
get(key: number): number {
if(this.map.has(key)){
let value = this.map.get(key);
this.map.delete(key);
this.map.set(key,value);
return value;
}else{
return -1;
}
}
put(key: number, value: number): void {
if(this.map.has(key)){
this.map.delete(key);
}
this.map.set(key,value);
if(this.map.size>this.capacity){
// 获取队头的第一个key
let firstKey = this.map.keys().next().value;
this.map.delete(firstKey);
}
}
}
总结
LRU缓存这道题目并不难,主要搞懂要使用什么数据结构做cache,才能达到好的效果