JavaScript算法题实现-146-LRU缓存机制——腾讯面试题库

出题指数(最大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

LeetCode原题目指路

题解

LRU缓存机制

Least Recently Used的缩写,即最近最少使用。

原理

选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。

假设内存只能容纳3个页大小,按照 7 0 1 2 0 3 0 4 的次序访问页。假设内存按照栈的方式来描述访问时间,在上面的,是最近访问的,在下面的是,最远时间访问的,LRU就是这样工作的。

img

思路

这个题不涉及复杂的算法,使用栈即可。如果要在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方法访问数据的时候,也算作使用数据,所以也应该刷新访问时间

猜你喜欢

转载自www.cnblogs.com/zhoujiayingvana/p/12683421.html
今日推荐