当前位置: 首页 > news >正文

LeetCode146:LRU缓存详解

题目Leetcode146

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

实现LRUCache类:

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

函数getput必须以O(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 # 必须存key:淘汰节点时,用key删除字典里的映射 self.value = value # 缓存存储的数据值 self.prev = None # 指向前驱节点 self.next = None # 指向后继节点 class LRUCache: def __init__(self, capacity: int): self.cache = dict() # 哈希字典:key→链表节点,实现O(1)查找节点 # 虚拟头结点、虚拟尾结点,固定不变,省去边界判断(不用判断节点是不是首尾) 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: int) -> int: """根据key获取缓存值,不存在返回-1;访问成功则将节点移到链表头部""" # 情况1:key不在缓存字典中,直接返回-1 if key not in self.cache: return -1 # 情况2:key存在,取出对应双向链表节点 target_node = self.cache[key] # 将当前访问节点移动到链表最头部(标记为最近使用) self.moveToHead(target_node) # 返回节点存储的值 return target_node.value def put(self, key: int, value: int) -> None: """新增/更新缓存数据""" # 分支1:全新key,需要新增节点 if key not in self.cache: # 1. 创建新双向链表节点 new_node = DLinkedNode(key, value) # 2. 字典中建立key和节点的映射 self.cache[key] = new_node # 3. 新节点插入双向链表头部(最新使用位置) self.addToHead(new_node) # 有效数量+1 self.size += 1 # 4. 超出缓存最大容量:淘汰最久未使用的尾部节点 if self.size > self.capacity: # 删除链表尾节点(最少使用节点) delete_node = self.removeTail() # 同步在字典中删除该key的映射 self.cache.pop(delete_node.key) # 有效数量-1 self.size -= 1 # 分支2:key已存在,只更新值+挪到头部 else: target_node = self.cache[key] # 更新节点存储的value target_node.value = value # 标记为最近使用,移到头部 self.moveToHead(target_node) def addToHead(self, node): """工具方法:把指定节点插入到虚拟头结点之后(链表首位)""" # 步骤1:绑定node的前后指针 node.prev = self.head node.next = self.head.next # 步骤2:修改原头部第一个节点的前驱指针,指向新node self.head.next.prev = node # 步骤3:头结点后继指向新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): """工具方法:删除链表尾部的真实节点(虚拟tail的前一个节点),返回被删节点""" # 获取待淘汰节点:虚拟尾结点的前驱 last_node = self.tail.prev # 从链表中移除该节点 self.removeNode(last_node) # 返回节点,供上层删除字典映射使用 return last_node

过程演示

整体架构

操作顺序:put (1,1) → put (2,2) → get (1) → put (3,3)


第 1 步:put (1, 1)
  1. 哈希表没有 key=1,创建新节点 (1,1)
  2. 哈希表:{1: 节点 1}
  3. 将节点插入双向链表头部 链表状态:head ↔ 节点 1 ↔ tail 当前数量:2 以内,无需淘汰。

第 2 步:put (2, 2)
  1. 哈希表没有 key=2,创建新节点 (2,2)
  2. 哈希表:{1: 节点 1,2: 节点 2}
  3. 插入链表头部 链表状态:head ↔ 节点 2 ↔ 节点 1 ↔ tail 当前数量刚好等于容量。

第 3 步:get (1)
  1. 在哈希表找到 key=1,对应节点 1
  2. 执行 moveToHead: ① 先把节点 1 从链表摘除 ② 再把节点 1 插到链表最头部 链表更新为:head ↔ 节点 1 ↔ 节点 2 ↔ tail 含义:节点 1 刚刚被访问,标记为最新使用。

第 4 步:put (3, 3)
  1. key=3 不存在,新建节点 3,插入链表头部
  2. 当前总数超出容量 2,触发淘汰机制: ① removeTail,删除 tail 前面的节点 2(最久未使用元素) ② 在哈希表中删除 key=2
  3. 最终状态: 链表:head ↔ 节点 3 ↔ 节点 1 ↔ tail 哈希表:{1: 节点 1,3: 节点 3}
http://www.jsqmd.com/news/1078443/

相关文章:

  • ComfyUI工作流原理--文生视频、图生视频
  • 宝丽金APP的本金核定减损工作已开展,请速登记办理。
  • AI 辅助团队协作:智能项目管理中的任务分配与进度预测实践
  • BKM系统有限间隙解:用射流密度近似KdV与Camassa-Holm方程
  • FlyOOBE:让老旧设备也能流畅运行Windows 11的实用工具
  • AI辅助开发工具链2026版
  • 广告灯箱厂商怎么选?2026年靠谱供应商实测分享
  • 数值计算稳定性:后向误差原理与通用收敛算法设计
  • 数据治理平台怎么选?五家头部产品核心能力、技术路线与落地场景全解析
  • 显式MPC参考轨迹压缩:降维原理、方法与实践指南
  • AI 智能组件生成:从设计规范到代码产出的自动化管线
  • Django进程:Cache Backends 透视与多级缓存穿透/击穿防御
  • 火山引擎多模态数据湖的制作思路
  • EF Core 向量搜索:将 RAG 核心能力直接带入 .NET 生态
  • OpenEMS开源能源管理系统:10分钟快速上手智能能源监控与优化
  • Kimi API合规接入指南:从认证到生产部署
  • 【观止·诗史汇 HarmonyOS 实战系列 04】诗文内容包:从 Markdown 到可检索的本地诗库
  • Android7 U盘插拔链路源码全解析(七)应用层MediaScanner与SAF
  • 分布式事务一致性:从 Seata AT 模式到可靠消息最终一致的架构选型
  • MuleSoft企业级AI编排:LLM服务化、治理与合规落地实践
  • AI 存储风向标:美光指引再超预期,费半盘后全线修复
  • Python 并发模型与异步编程:从 GIL 约束到协程调度的工程实践
  • 游戏开发资源大全:一个仓库搞定所有学习资料
  • python基于框架flask模板template实现
  • react源码学习之Scheduler
  • Stable Diffusion提示词工程实战:从结构编码到动态权重调度
  • 可组合型数据团队:AI时代的数据交付新范式
  • TCN理解
  • 闲来做了一个轻量化在线计算器小项目,记录一下开发初衷
  • 5款英文降AI率平台实测推荐