出题指数(最大5):????
题目
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get
和 写入数据 put
。
获取数据 get(key)
- 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value)
- 如果密钥已经存在,则变更其数据值;如果密钥不存在,则插入该组「密钥/数据值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
进阶:
你是否可以在 O(1) 时间复杂度内完成这两种操作?
示例:
LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得密钥 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得密钥 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4
题解
LRU缓存机制
Least Recently Used的缩写,即最近最少使用。
原理
选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。
假设内存只能容纳3个页大小,按照 7 0 1 2 0 3 0 4 的次序访问页。假设内存按照栈的方式来描述访问时间,在上面的,是最近访问的,在下面的是,最远时间访问的,LRU就是这样工作的。
思路
这个题不涉及复杂的算法,使用栈即可。如果要在O(1)时间内完成,考虑ES6的Map
对象。
JavaScript实现
普通版
时间复杂度不一定是O(1)
/**
* @param {number} capacity
*/
var LRUCache = function (capacity) {
this.capacity = capacity;
// 存放key的index
this.stack = [];
// 存放key和value
this.secretKey = {};
};
/**
* @param {number} key
* @return {number}
*/
LRUCache.prototype.get = function (key) {
if (key in this.secretKey) {
// 更新stack
this.stack.splice(this.stack.indexOf(key), 1);
this.stack.unshift(key);
return this.secretKey[key];
}
else return -1;
};
/**
* @param {number} key
* @param {number} value
* @return {void}
*/
LRUCache.prototype.put = function (key, value) {
// key存在,仅修改值
if (key in this.secretKey) {
this.secretKey[key] = value;
// 更新stack
this.stack.splice(this.stack.indexOf(key), 1);
this.stack.unshift(key);
}
// key不存在且栈未满
else if (this.stack.length < this.capacity) {
this.secretKey[key] = value;
this.stack.unshift(key);
}
// key不存在且栈满
else {
// 删除key
delete this.secretKey[this.stack[this.capacity - 1]]
this.secretKey[key] = value;
this.stack.pop();
this.stack.unshift(key);
}
};
/**
* 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)
*/
let cache = new LRUCache(2);
cache.put(1, 1);
cache.put(2, 2);
console.log("cache.get(1)", cache.get(1))// 返回 1
cache.put(3, 3);// 该操作会使得密钥 2 作废
console.log(cache.stack);
console.log("cache.get(2)", cache.get(2))// 返回 -1 (未找到)
cache.put(4, 4);// 该操作会使得密钥 1 作废
console.log("cache.get(1)", cache.get(1))// 返回 -1 (未找到)
console.log("cache.get(3)", cache.get(3))// 返回 3
console.log("cache.get(4)", cache.get(4))// 返回 4
进阶版
利用ES6的Map
对象,时间复杂度应该是O(1)
一个Map对象在迭代时会根据对象中元素的插入顺序来进行
// 一个Map对象在迭代时会根据对象中元素的插入顺序来进行
// 新添加的元素会被插入到map的末尾,整个栈倒序查看
class LRUCache {
constructor(capacity) {
this.secretKey = new Map();
this.capacity = capacity;
}
get(key) {
if (this.secretKey.has(key)) {
let tempValue = this.secretKey.get(key);
this.secretKey.delete(key);
this.secretKey.set(key, tempValue);
return tempValue;
}
else return -1;
}
put(key, value) {
// key存在,仅修改值
if (this.secretKey.has(key)) {
this.secretKey.delete(key);
this.secretKey.set(key, value);
}
// key不存在,cache未满
else if(this.secretKey.size<this.capacity){
this.secretKey.set(key, value);
}
// 添加新key,删除旧key
else{
this.secretKey.set(key,value);
// 删除map的第一个元素,即为最长未使用的
this.secretKey.delete(this.secretKey.keys().next().value);
}
}
}
let cache = new LRUCache(2);
cache.put(1, 1);
cache.put(2, 2);
console.log("cache.get(1)", cache.get(1))// 返回 1
cache.put(3, 3);// 该操作会使得密钥 2 作废
console.log("cache.get(2)", cache.get(2))// 返回 -1 (未找到)
cache.put(4, 4);// 该操作会使得密钥 1 作废
console.log("cache.get(1)", cache.get(1))// 返回 -1 (未找到)
console.log("cache.get(3)", cache.get(3))// 返回 3
console.log("cache.get(4)", cache.get(4))// 返回 4
做题心得
笔者的朋友在面试蚂蚁金服的时候遇到了类似的题目,所以考的概率应该蛮大的
get
方法访问数据的时候,也算作使用数据,所以也应该刷新访问时间
原文地址:https://www.cnblogs.com/zhoujiayingvana/p/12683421.html
时间: 2024-11-09 02:48:59