news 2026/5/26 4:05:12

【每日算法】LeetCode 146. LRU 缓存机制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【每日算法】LeetCode 146. LRU 缓存机制

对前端开发者而言,学习算法绝非为了“炫技”。它是你从“页面构建者”迈向“复杂系统设计者”的关键阶梯。它将你的编码能力从“实现功能”提升到“设计优雅、高效解决方案”的层面。从现在开始,每天投入一小段时间,结合前端场景去理解和练习,你将会感受到自身技术视野和问题解决能力的质的飞跃。------ 算法:资深前端开发者的进阶引擎

LeetCode 146. LRU 缓存机制

1. 题目描述

1.1 问题要求

设计一个LRU(最近最少使用)缓存机制,实现以下两个操作:

  • get(key):如果密钥key存在于缓存中,则返回密钥的值,否则返回-1
  • put(key, value):如果密钥不存在,则写入数据;当缓存容量达到上限时,删除最久未使用的数据

1.2 注意事项

  • 所有操作(getput)必须在O(1)时间复杂度内完成
  • 当缓存达到容量上限时,put操作需要淘汰最久未使用的数据
  • 即使只是查询 (get) 数据,该数据也会变为"最近使用"的数据

2. 问题分析

2.1 核心需求分析

LRU缓存的核心需求是:快速访问 + 快速淘汰。这意味着我们需要:

  1. 快速查找:通过key快速找到对应值(哈希表的特性)
  2. 快速删除和插入:能够快速将某个元素移到"最近使用"位置,或在容量满时删除最久未使用的元素(链表的特性)
  3. 维护访问顺序:记录每个key的访问时间顺序

2.2 前端视角的理解

在前端开发中,LRU缓存的应用非常广泛:

  • 浏览器缓存机制
  • Vue/React的keep-alive组件
  • 图片/资源缓存策略
  • API响应缓存

3. 解题思路

3.1 可行思路分析

3.1.1 思路一:数组/对象 + 时间戳(不可行)
  • 使用对象存储键值对,记录每个key的最后访问时间
  • 每次操作时更新时间戳,淘汰时遍历查找最旧的时间
  • 缺点:淘汰时需要O(n)遍历,不满足O(1)要求
3.1.2 思路二:Map的天然特性(ES6 Map)
  • Map按照插入顺序维护键值对,最后插入的在最后
  • 每次访问时先删除再重新插入,可以维护顺序
  • 复杂度:O(1)时间完成所有操作
3.1.3 思路三:哈希表 + 双向链表(经典解法)
  • 哈希表提供O(1)的查找
  • 双向链表提供O(1)的删除和插入,维护访问顺序
  • 头节点表示最近访问,尾节点表示最久未访问

3.2 最优解选择

思路三(哈希表+双向链表)是最经典的LRU实现方案,虽然ES6的Map也可以实现,但了解底层原理对理解缓存机制更有帮助。

4. 各思路代码实现

4.1 思路二:ES6 Map实现

classLRUCache{constructor(capacity){this.capacity=capacity;this.cache=newMap();// Map天然保持插入顺序}get(key){if(!this.cache.has(key))return-1;// 获取值constvalue=this.cache.get(key);// 删除后重新插入,保证在Map最后(最近使用)this.cache.delete(key);this.cache.set(key,value);returnvalue;}put(key,value){// 如果key已存在,先删除if(this.cache.has(key)){this.cache.delete(key);}// 如果容量已满,删除第一个(最久未使用)elseif(this.cache.size>=this.capacity){constfirstKey=this.cache.keys().next().value;this.cache.delete(firstKey);}// 插入新值this.cache.set(key,value);}}

4.2 思路三:哈希表 + 双向链表实现

// 双向链表节点classListNode{constructor(key,value){this.key=key;this.value=value;this.prev=null;this.next=null;}}classLRUCache{constructor(capacity){this.capacity=capacity;this.cache=newMap();// 哈希表:key -> 链表节点this.size=0;// 创建虚拟头尾节点,简化边界判断this.head=newListNode(0,0);// 最近使用this.tail=newListNode(0,0);// 最久未使用this.head.next=this.tail;this.tail.prev=this.head;}// 获取节点get(key){if(!this.cache.has(key))return-1;constnode=this.cache.get(key);// 移动到链表头部(表示最近使用)this.moveToHead(node);returnnode.value;}// 插入节点put(key,value){if(this.cache.has(key)){// 更新已存在的节点constnode=this.cache.get(key);node.value=value;this.moveToHead(node);}else{// 创建新节点constnewNode=newListNode(key,value);this.cache.set(key,newNode);this.addToHead(newNode);this.size++;// 如果超过容量,删除尾部节点if(this.size>this.capacity){consttailNode=this.removeTail();this.cache.delete(tailNode.key);this.size--;}}}// 将节点移动到头部(最近使用)moveToHead(node){this.removeNode(node);this.addToHead(node);}// 从链表中删除节点removeNode(node){node.prev.next=node.next;node.next.prev=node.prev;}// 在头部添加节点addToHead(node){node.prev=this.head;node.next=this.head.next;this.head.next.prev=node;this.head.next=node;}// 删除尾部节点(最久未使用)removeTail(){consttailNode=this.tail.prev;this.removeNode(tailNode);returntailNode;}}

5. 各实现思路的复杂度、优缺点对比表格

实现方案时间复杂度空间复杂度优点缺点适用场景
ES6 Map实现get: O(1)
put: O(1)
O(capacity)1. 代码简洁,易于理解
2. 利用语言特性
3. 开发效率高
1. 隐藏了底层原理
2. Map内部实现不透明
实际项目开发、快速原型
哈希表+双向链表get: O(1)
put: O(1)
O(capacity)1. 展示完整缓存机制原理
2. 面试中展现扎实基础
3. 可控性更强
1. 代码相对复杂
2. 需要手动维护链表
面试场景、学习缓存原理、需要定制化场景

6. 总结

6.1 技术要点总结

  1. LRU核心思想:最近使用的数据在未来更可能被使用,应该保留
  2. 数据结构选择:哈希表提供快速查找,链表维护使用顺序
  3. 边界处理:使用虚拟头尾节点可显著简化代码逻辑
  4. 时间复杂度保证:所有操作必须为O(1),这是LRU缓存设计的核心要求

6.2 前端实际应用场景

6.2.1 浏览器缓存
  • 浏览器对静态资源(JS、CSS、图片)的缓存采用类似LRU的策略
  • HTTP缓存头(Cache-Control)控制缓存行为
6.2.2 Vue Keep-Alive组件
<template> <keep-alive :max="10"> <!-- 最多缓存10个组件实例 --> <component :is="currentComponent"></component> </keep-alive> </template>

Vue的keep-alive内部实现就使用了LRU缓存策略,当超过最大缓存数量时,自动销毁最久未使用的组件实例。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/26 6:34:32

SQL语言家族入门指南:标准SQL、T-SQL与PL/SQL详解

SQL语言家族入门指南&#xff1a;标准SQL、T-SQL与PL/SQL详解 对于数据库初学者来说&#xff0c;SQL语言的各种变体常常让人困惑。本文将为你详细解析标准SQL、T-SQL和PL-SQL的概念及其应用场景。 标准SQL 概念 标准SQL (Structured Query Language) 是由ANSI和ISO标准化组织制…

作者头像 李华
网站建设 2026/5/25 8:38:22

Thymeleaf 项目创建及请求响应过程解析

创建项目 1. 使用Spring Initializr创建项目 访问 https://start.spring.io/ 或使用IDE的Spring Initializr功能&#xff0c;选择以下依赖&#xff1a; Spring WebThymeleafSpring Boot DevTools&#xff08;可选&#xff0c;用于开发时热部署&#xff09; 项目结构 src/main/j…

作者头像 李华
网站建设 2026/5/24 23:58:19

铝箔与铝制品自动检测:基于YOLO13-C3k2-ConvFormer的智能分类系统详解

1. 铝箔与铝制品自动检测&#xff1a;基于YOLO13-C3k2-ConvFormer的智能分类系统详解 1.1. 系统概述 铝制品在现代工业中应用广泛&#xff0c;从包装材料到电子元件&#xff0c;从建筑材料到航空航天部件&#xff0c;都离不开铝及其合金制品。然而&#xff0c;铝制品在生产过…

作者头像 李华
网站建设 2026/5/25 23:04:41

【稀缺技术公开】:R实现量子模拟飞秒级时间分辨率的秘密路径

第一章&#xff1a;R 量子模拟的测量精度在量子计算与量子模拟的研究中&#xff0c;测量精度是决定实验结果可信度的关键因素。R语言凭借其强大的统计分析能力与可视化工具&#xff0c;被广泛应用于量子模拟数据的后处理与误差分析中。通过精确建模测量噪声、系统漂移和量子态坍…

作者头像 李华
网站建设 2026/5/25 11:48:35

【临床数据R语言亚组分析实战】:掌握高效亚组挖掘技巧与代码实现

第一章&#xff1a;临床数据亚组分析概述 在临床研究中&#xff0c;亚组分析是一种重要的统计方法&#xff0c;用于探索治疗效应在不同患者群体中的异质性。通过对特定人口学特征、疾病严重程度或生物标志物等变量进行分层&#xff0c;研究人员能够识别出对干预措施反应更显著的…

作者头像 李华
网站建设 2026/5/24 16:28:17

为什么90%的AI语音项目都卡在音频质检?Dify 1.7.0给出答案

第一章&#xff1a;为什么90%的AI语音项目都卡在音频质检&#xff1f;在AI语音系统开发中&#xff0c;模型训练只是冰山一角&#xff0c;真正决定项目成败的是隐藏在背后的音频质检环节。大量团队在数据采集后直接进入训练阶段&#xff0c;却忽视了原始音频中存在的噪声、静音段…

作者头像 李华