LeetCode 146. LRU Cache 题解

LeetCode 146. LRU Cache 题解

题目描述

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。

实现 LRUCache 类:

  • LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1
  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

示例 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]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解题思路

使用双向链表 + 哈希表实现:

  • 双向链表:按使用顺序排列,最近使用的在头部,最久未使用的在尾部
  • 哈希表:快速查找节点

代码实现

python 复制代码
class DLinkedNode:
    def __init__(self, key=0, value=0):
        self.key = key
        self.value = value
        self.prev = None
        self.next = None

class LRUCache:
    def __init__(self, capacity):
        self.cache = dict()  # key -> node
        self.head = DLinkedNode()  # 虚拟头节点
        self.tail = DLinkedNode()  # 虚拟尾节点
        self.head.next = self.tail
        self.tail.prev = self.head
        self.capacity = capacity
        self.size = 0
    
    def get(self, key):
        if key not in self.cache:
            return -1
        # 将访问的节点移到头部
        node = self.cache[key]
        self.moveToHead(node)
        return node.value
    
    def put(self, key, value):
        if key in self.cache:
            # 更新值并移到头部
            node = self.cache[key]
            node.value = value
            self.moveToHead(node)
        else:
            # 创建新节点
            node = DLinkedNode(key, value)
            self.cache[key] = node
            self.addToHead(node)
            self.size += 1
            
            # 超出容量,删除尾部节点
            if self.size > self.capacity:
                removed = self.removeTail()
                del self.cache[removed.key]
                self.size -= 1
    
    def addToHead(self, node):
        node.prev = self.head
        node.next = self.head.next
        self.head.next.prev = node
        self.head.next = node
    
    def removeNode(self, node):
        node.prev.next = node.next
        node.next.prev = node.prev
    
    def moveToHead(self, node):
        self.removeNode(node)
        self.addToHead(node)
    
    def removeTail(self):
        node = self.tail.prev
        self.removeNode(node)
        return node

复杂度分析

  • 时间复杂度:get 和 put 操作都是 O(1)
  • 空间复杂度:O(capacity)

测试案例

python 复制代码
# 测试案例 1
lru = LRUCache(2)
lru.put(1, 1)
lru.put(2, 2)
assert lru.get(1) == 1  # 返回 1
lru.put(3, 3)  # 驱逐 2
assert lru.get(2) == -1  # 返回 -1
lru.put(4, 4)  # 驱逐 1
assert lru.get(1) == -1  # 返回 -1
assert lru.get(3) == 3  # 返回 3
assert lru.get(4) == 4  # 返回 4

总结

本题是 LRU 缓存的经典实现。

关键点:

  • 双向链表维护使用顺序
  • 哈希表实现 O(1) 查找
  • 虚拟头尾节点简化操作
  • 移动节点到头部表示最近使用
  • 删除尾部节点表示逐出最久未使用
相关推荐
Asize14 分钟前
438. 找到字符串中所有字母异位词
算法
Asize21 分钟前
283. 移动零
算法
船厂电气自动化ai大模型2 小时前
AI大模型与数学·第57课 傅里叶全套工具链综合实战:串联级数/连续变换/DFT/FFT,图像、音频、扩散模型完整例题
数据结构·人工智能·深度学习·算法·机器学习
人工智能培训3 小时前
人工智能数据安全下的个人信息保护实践方案
大数据·人工智能·算法·生活
元启数宇4 小时前
幕墙AI设计算法逻辑:元启数宇如何智能分格
人工智能·算法
宵时待雨4 小时前
优选算法专题16:多源BFS
算法·宽度优先
重生之后端学习4 小时前
53. 最大子数组和[中等]✅
java·数据结构·算法·leetcode·职场和发展
INGNIGHT4 小时前
1908 · 布尔表达式求值(stack单调栈&dfs)
开发语言·c++·算法
lucas_AI5 小时前
把表格压成 64 个 token,长文档问答反而更准了:先找表,再看数
人工智能·深度学习·算法
Zzz 小生5 小时前
Lazy Theta*:把昂贵的视线检测留到“真正需要”时再做
人工智能·算法·贪心算法·推荐算法