[LeetCode 146. LRU缓存机制] | 刷题打卡

218 阅读3分钟

什么是LRU?

缓存在计算机网络上随处可见,例如:当我们首次访问一个网页时,打开很慢,但当我们再次打开这个网页时,打开就很快。

这就涉及缓存在浏览器上的应用:浏览器缓存。当我们打开一个网页时,它会在发起真正的网络请求前,查询浏览器缓存,看是否有要请求的文件,如果有,浏览器将会拦截请求,返回缓存文件,并直接结束请求,不会再去服务器上下载。如果不存在,才会去服务器请求。

其实,浏览器中的缓存是一种在本地保存资源副本,它的大小是有限的,当我们请求数过多时,缓存空间会被用满,此时,继续进行网络请求就需要确定缓存中哪些数据被保留,哪些数据被移除,这就是浏览器缓存淘汰策略,最常见的淘汰策略有 FIFO(先进先出)、LFU(最少使用)、LRU(最近最少使用)。

LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。

题目

运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制 。 实现 LRUCache 类:

  • LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
  • void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?

示例

  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]]

  2. 输出:[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

AC代码

  1. 数组+对象实现方式
var LRUCache = function(capacity) {
    this.keys = []
    this.cache = Object.create(null)
    this.capacity = capacity
};

LRUCache.prototype.get = function(key) {
    if(this.cache[key]) {
        // 调整位置
        remove(this.keys, key)
        this.keys.push(key)
        return this.cache[key]
    }
    return -1
};

LRUCache.prototype.put = function(key, value) {
    if(this.cache[key]) {
        // 存在即更新
        this.cache[key] = value
        remove(this.keys, key)
        this.keys.push(key)
    } else {
        // 不存在即加入
        this.keys.push(key)
        this.cache[key] = value
        // 判断缓存是否已超过最大值
        if(this.keys.length > this.capacity) {
            removeCache(this.cache, this.keys, this.keys[0])
        }
    }
};

// 移除 key
function remove(arr, key) {
    if (arr.length) {
        const index = arr.indexOf(key)
        if (index > -1) {
            return arr.splice(index, 1)
        }
    }
}

// 移除缓存中 key
function removeCache(cache, keys, key) {
    cache[key] = null
    remove(keys, key)
}

  1. Map: 利用 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)
};

题目链接:146. LRU 缓存机制

本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情:juejin.cn/post/693314…