面试题 Interview Question
实现一个
LRUCache
类,支持get(key)
和put(key, value)
方法,均在 O(1) 时间复杂度内完成,并在缓存满时淘汰最近最少使用的项。 力扣Implement an
LRUCache
class withget(key)
andput(key, value)
methods, each operating in O(1) time, and evicting the least-recently-used entry when capacity is exceeded. LeetCode
要求 Requirements
LRUCache(capacity)
构造函数接收一个正整数capacity
,表示缓存的最大容量
The constructorLRUCache(capacity)
takes a positive integercapacity
indicating the cache’s maximum size.get(key)
:- 如果
key
存在,返回对应的value
并将该项标记为最近使用
Ifkey
exists, return itsvalue
and mark it as most recently used - 如果不存在,返回
-1
If not found, return-1
.
- 如果
put(key, value)
:- 如果
key
已存在,更新其value
并标记为最近使用
Ifkey
exists, update itsvalue
and mark it as most recently used - 如果
key
不存在且缓存已满,则移除最久未使用的项,再插入新key-value
对
Ifkey
is absent and cache is full, remove the least-recently-used item before inserting the new pair.
- 如果
- 所有操作应具有 O(1) 时间复杂度
All operations must run in O(1) time, requiring a doubly linked list for order tracking and a hash map for fast lookup.
参考答案 Reference Solution
class LRUCache {
constructor(capacity) {
this.capacity = capacity;
this.cache = new Map(); // Hash map for O(1) lookups
}
get(key) {
if (!this.cache.has(key)) {
return -1;
}
const value = this.cache.get(key);
this.cache.delete(key); // Remove and re-insert to update recency
this.cache.set(key, value);
return value;
}
put(key, value) {
if (this.cache.has(key)) {
this.cache.delete(key);
}
this.cache.set(key, value); // Insert as most recently used
if (this.cache.size > this.capacity) {
// Evict least recently used key (first item in Map)
const lruKey = this.cache.keys().next().value;
this.cache.delete(lruKey);
}
}
}
- 以上方案利用现代 JavaScript 中
Map
保持插入顺序的特性来模拟双向链表,无需手写节点结构,但依然满足 O(1) 操作
This approach leverages the insertion-order guarantee of JavaScript’s modernMap
to emulate a doubly linked list without manually implementing node structures, while still achieving O(1) operations. Reddit GeeksforGeeks - 对于更底层的面试要求,可使用显式的双向链表+普通对象/
Map
组合来展示链表节点移动的思路
For more low-level interview requirements, you can use an explicit doubly linked list combined with plain objects or aMap
to demonstrate the mechanics of moving list nodes.
示例 Example
const cache = new LRUCache(2);
cache.put(1, 'A'); // 缓存: {1=A}
cache.put(2, 'B'); // 缓存: {1=A, 2=B}
cache.get(1); // 返回 'A', 更新顺序: {2=B, 1=A}
cache.put(3, 'C'); // 容量已满, 淘汰 LRU 键 2 -> 缓存: {1=A, 3=C}
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 'D'); // 淘汰键 1 -> 缓存: {3=C, 4=D}
cache.get(1); // 返回 -1
cache.get(3); // 返回 'C'
cache.get(4); // 返回 'D'
面试考察点 Interview Focus
- 时间/空间复杂度:理解如何在 O(1) 时间内完成缓存查找、更新与淘汰。
Time/space complexity: how to achieve O(1) for get/put/evict. - 数据结构设计:双向链表+哈希表组合或利用
Map
保序机制的巧思。
Data-structure design: doubly linked list + hash map, or leveragingMap
’s insertion order. - 代码可靠性:边界条件(如容量为 0、重复
put
、get
不存在的键)处理。
Robustness: handling edge cases (capacity 0, duplicate puts, missing gets).