
Python 实现 LRU 缓存,核心在于 O(1) 时间复杂度完成 get 和 put 操作,同时自动淘汰最久未使用的项。标准解法是用 OrderedDict(Python 3.7+ 中普通 dict 也保持插入顺序,但 OrderedDict 提供了 move_to_end() 这一关键能力)。
为什么用 OrderedDict 而不是普通 dict?
OrderedDict 支持在 O(1) 时间内把某个 key 移动到末尾(move_to_end(key, last=True)),这正好对应“访问即更新为最近使用”。普通 dict 虽有序,但没有内置方法高效完成这一操作;手动删再插会多一次哈希查找和重建节点,逻辑冗余且易出错。
LRU 缓存的关键行为逻辑
- get(key):命中则返回值,并将该 key 移至末尾(标记为最新使用);未命中返回 -1
- put(key, value):若 key 已存在,更新值并移至末尾;若不存在,插入新项;插入后若超出容量,删除开头的项(最久未使用)
- 注意:put 时如果 key 存在,不算新增,不触发容量检查;只有新增 key 才可能触发淘汰
简洁可运行的实现代码
from collections import OrderedDict
<p>class LRUCache:
def <strong>init</strong>(self, capacity: int):
self.cache = OrderedDict()
self.capacity = capacity</p><pre class="brush:php;toolbar:false;"><pre class="brush:php;toolbar:false;">def get(self, key: int) -> int:
if key not in self.cache:
return -1
self.cache.move_to_end(key) # 标记为最近使用
return self.cache[key]
def put(self, key: int, value: int) -> None:
if key in self.cache:
self.cache.move_to_end(key)
self.cache[key] = value
if len(self.cache) > self.capacity:
self.cache.popitem(last=False) # 删除最久未使用的(开头)</code>
面试中容易被追问的点
- 时间/空间复杂度:get 和 put 均为 O(1),空间 O(capacity)
- 能否不用 OrderedDict 自己实现?:可以,用双向链表 + 哈希表(dict),链表节点存 key-value,dict 映射 key → 节点指针;每次访问需断开、插入链表尾部,删除头节点;代码量大,但体现底层理解
-
线程安全吗?:不安全;如需并发支持,加锁(如
threading.Lock)或改用 <code>functools.lru_cache(仅适用于函数级缓存) -
capacity = 0 怎么办?:初始化时应允许,后续所有 put 都立即淘汰,get 永远 -1;代码中无需特殊处理,
popitem在空 dict 会报错,但容量为 0 时 put 后 len=1 > 0,会触发 pop,此时 OrderedDict 非空,安全









