一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。
146. LRU 缓存
请你设计并实现一个满足 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 <= 30000 <= key <= 100000 <= value <= 10^5- 最多调用
2 * 10^5次 get 和 put
思路:
本题借助Map的特性来实现LRU。根据MDN的描述,Map对象保存键值对,并且能够记住键的原始插入顺序。因此插入的顺序就是最近使用的顺序。
当获取值时,直接get获取,然后删除掉当前值,再重新插入到map中,这样就实现了最近原则。
当设置值时,如果当前值已存在,则先删除再插入;如果当前缓存已满员,则删除掉最先插入的一条数据,再插入当前值。需要注意的是,可以通过以下方式来获取map中的第一条值。
const map = new Map();
const first_value = map.keys().next().value;
MDN中说到,keys() 返回一个引用的 Iterator 对象。它包含按照 顺序 插入 Map 对象中每个元素的key值。获取迭代器的第一个键的值就是上述写法。同理,values()也有类似的作用。
最终的代码如下:
Map
/**
* @param {number} capacity
*/
var LRUCache = function(capacity) {
this.cache = new Map();
this.capacity = capacity;
};
/**
* @param {number} key
* @return {number}
*/
LRUCache.prototype.get = function(key) {
if (this.cache.has(key)) {
let temp = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, temp);
return temp;
}
return -1;
};
/**
* @param {number} key
* @param {number} value
* @return {void}
*/
LRUCache.prototype.put = function(key, value) {
if (this.cache.has(key)) {
this.cache.delete(key);
} else if (this.cache.size >= this.capacity) {
this.cache.delete(this.cache.keys().next().value);
}
this.cache.set(key, value);
};
/**
* Your LRUCache object will be instantiated and called as such:
* var obj = new LRUCache(capacity)
* var param_1 = obj.get(key)
* obj.put(key,value)
*/
总结
LRU算法思想在vue的keep-alive组件中有被使用。本题也是面试中常被问到的高频面试题。因此需要完全掌握。
更进一步的,也需要我们了解vue的keep-alive组件的源码是如何写的,学习优秀的源码,我们才可以走的更远。