标准答案

  1. LRU 表示 Least Recently Used,容量满时淘汰最久没有被访问的数据。
  2. get 命中时不仅要返回值,还要刷新该 key 的使用顺序。
  3. put 写入已存在 key 时要更新值,并把它移动到最新位置。
  4. 容量超出时删除最旧的 key。
  5. Map 版本适合理解核心规则,高性能版本通常用哈希表加双向链表。

题目解析

LRU 常见于接口缓存、图片缓存、编译缓存和页面状态缓存。它解决的是容量有限时保留更可能再次访问的数据,而不是无限缓存。

Map 的插入顺序能表达“新旧”。删除后重新 set,就可以把一个 key 移到最新位置;Map.keys().next().value 可以拿到最旧 key。

如果面试继续要求 O(1) 移动和删除,就要从 Map 简化版升级到哈希表加双向链表:哈希表负责定位节点,链表负责维护访问顺序。

代码示例

Map 简化版可以清楚展示访问刷新和容量淘汰两个动作。

JavaScript
class LRUCache {
  constructor(capacity) {
    this.capacity = capacity
    this.cache = new Map()
  }

  get(key) {
    if (!this.cache.has(key)) {
      return undefined
    }

    const value = this.cache.get(key)
    this.cache.delete(key)
    this.cache.set(key, value)
    return value
  }

  put(key, value) {
    if (this.cache.has(key)) {
      this.cache.delete(key)
    }

    this.cache.set(key, value)

    if (this.cache.size > this.capacity) {
      const oldestKey = this.cache.keys().next().value
      this.cache.delete(oldestKey)
    }
  }
}

常见误区

  • get 命中后没有刷新顺序,导致常用数据仍然可能被淘汰。
  • 只存数据不限制容量,实际上没有实现 LRU 淘汰。
  • 没有说明 Map 简化版和哈希表加双向链表版本的性能差异。

作者信息