面试遇到算法题:实现LRU缓存

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

这是一道大厂面试高频出现的算法题,难度为⭐️⭐️⭐️,属于中等,老铁们来一起看看这个题该怎么解?

1. 原题再现

没有废话,翠花,上酸菜!

2. 具体实现

为了实现一个满足 LRU (最近最少使用)缓存约束的数据结构,我们需要一个能够快速访问、更新和删除的数据结构,V 哥想到了用哈希表,因为哈希表提供了快速的查找能力,但是它不能保持元素的顺序;而双向链表可以保持元素的顺序,并且可以在 O(1) 时间复杂度内进行插入和删除操作。因此, V哥采用结合使用哈希表和双向链表来实现LRU缓存。

以下是 Java 代码实现:

import java.util.HashMap;class Node {int key;int value;Node prev;Node next;public Node(int key, int value) {this.key = key;this.value = value;}
}public class LRUCache {private HashMap<Integer, Node> cache;private Node head, tail;private int capacity;private int count;public LRUCache(int capacity) {this.capacity = capacity;this.cache = new HashMap<>();this.head = new Node(0, 0);this.tail = new Node(0, 0);this.head.next = this.tail;this.tail.prev = this.head;this.count = 0;}public int get(int key) {Node node = cache.get(key);if (node == null) {return -1;}moveToHead(node);return node.value;}public void put(int key, int value) {Node node = cache.get(key);if (node == null) {Node newNode = new Node(key, value);cache.put(key, newNode);addNode(newNode);count++;if (count > capacity) {Node toDel = popTail();cache.remove(toDel.key);count--;}} else {node.value = value;moveToHead(node);}}private void addNode(Node node) {node.prev = head;node.next = head.next;head.next.prev = node;head.next = node;}private void removeNode(Node node) {node.prev.next = node.next;node.next.prev = node.prev;}private void moveToHead(Node node) {removeNode(node);addNode(node);}private Node popTail() {Node res = tail.prev;removeNode(res);return res;}
}

使用示例:

public class Main {public static void main(String[] args) {LRUCache lRUCache = new LRUCache(2);lRUCache.put(1, 1); // 缓存是 {1=1}lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}System.out.println(lRUCache.get(1));    // 返回 1lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}System.out.println(lRUCache.get(2));    // 返回 -1 (未找到)lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}System.out.println(lRUCache.get(1));    // 返回 -1 (未找到)System.out.println(lRUCache.get(3));    // 返回 3System.out.println(lRUCache.get(4));    // 返回 4}
}

输出结果应该与题目中的示例输出一致。这个实现使用了哈希表来快速查找节点,同时使用双向链表来维护节点的顺序和实现快速插入和删除操作。这样,我们就可以在 O(1) 的时间复杂度内完成 get 和 put 操作。

实现过程和步骤如下:

  1. 定义一个 Node 类,用于双向链表的节点,包含 key、value 以及前驱和后继节点的引用。

  2. 在 LRUCache 类中,定义一个 capacity 表示缓存的最大容量,一个 count 表示当前缓存中的节点数量,一个 cache 哈希表用于存储键和节点的映射,以及 head 和 tail 虚拟节点用于简化双向链表的操作。

  3. 实现 get 方法,首先在哈希表中查找键对应的节点,如果节点不存在,返回 -1。如果节点存在,则将该节点移动到链表的头部,表示最近被使用,然后返回节点的值。

  4. 实现 put 方法,如果键在哈希表中不存在,创建一个新的节点,并将其添加到链表的头部,同时添加到哈希表中。如果插入后节点数量超过了容量,则需要移除链表尾部的节点,并从哈希表中删除对应的条目。如果键已经存在,则更新对应的节点值,并将其移动到链表头部。

  5. addNode 方法用于将节点添加到链表头部,removeNode 方法用于从链表中移除节点,moveToHead 方法用于将节点移动到链表头部,popTail 方法用于移除链表尾部的节点。

  6. 在 Main 类的 main 方法中,我们创建了一个 LRUCache 实例,并执行了一系列的 put 和 get 操作来演示其功能。

V哥认为这个实现确保了 get 和 put 操作的平均时间复杂度为O(1)。get 操作直接通过哈希表查找节点,而 put 操作中,无论是更新现有节点还是添加新节点,都涉及到对双向链表的操作,这些操作的时间复杂度都是 O(1)。当缓存达到容量上限时,put 操作会移除最久未使用的节点,这也是 O(1) 时间复杂度的操作。

3. 小结一下

V哥的这个实现的关键在于维护一个双向链表,它可以帮助我们快速地访问、更新和删除最近最少使用的节点,同时使用哈希表来提供快速的查找能力。这样,我们就可以在 O(1) 的时间复杂度内完成所有的缓存操作。哈哈干净利索,回答完毕。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/2963.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

亚远景科技-什么是R.A.S.I.C角色职权矩阵

什么是 R.A.S.I.C角色职权矩阵 在流程定义过程中&#xff0c;亚远景科技推荐使用RASIC 矩阵。RASIC 矩阵是一个非常有用的管理方法。可以明确流程定义中的角色和其相关责任。 "RASIC" 是"Responsible" 、"Accountable" 、"Supportive"…

JS 添加数组元素( 4种方法 )

No.内容链接1Openlayers 【入门教程】 - 【源代码示例300】 2Leaflet 【入门教程】 - 【源代码图文示例 150】 3Cesium 【入门教程】 - 【源代码图文示例200】 4MapboxGL【入门教程】 - 【源代码图文示例150】 5前端就业宝典 【面试题详细答案 1000】 文章目录 一、四种…

Spring Boot 集成 EasyExcel 3.x

Spring Boot 集成 EasyExcel 3.x Spring Boot 集成 EasyExcel 3.x 本章节将介绍 Spring Boot 集成 EasyExcel&#xff08;优雅实现Excel导入导出&#xff09;。 &#x1f916; Spring Boot 2.x 实践案例&#xff08;代码仓库&#xff09; 介绍 EasyExcel 是一个基于 Java 的、…

npm详解:Node.js的包管理器

npm&#xff08;Node Package Manager&#xff09;是Node.js的包管理器&#xff0c;它允许您安装、更新、删除和发布Node.js软件包。npm是Node.js生态系统中非常重要的组成部分&#xff0c;它使得开发人员能够轻松共享和重用代码&#xff0c;从而提高了开发效率和代码质量。 在…

HZNUCTF -- web

HZNUCTF第五届校赛实践赛初赛 Web方向 WriteUp-CSDN博客 ezssti 下载文件 访问 /login 可由源代码中看到 Eval 函数 &#xff0c;可以任意命令执行 按照格式&#xff0c;可执行命令 POST &#xff1a;name{{.Eval "env"}} 可以得到flag &#xff08;尝试ls 只能列出…

「ChatGPT」掀起新一轮AI热潮!超越GPT-4 Turbo,商汤日日新大升级!

目录 拳打 GPT-4 Turbo &#xff0c;脚踢 DALLE 3 端侧大模型&#xff0c;唯快不破 AI 应用落地需要一个即插即用的大模型超市 并不存在 AI 这个行业&#xff0c;只有 AI行业&#xff0c;强调 AI 需要与传统产业合作&#xff0c;这种关系是结合与赋能&#xff0c;而不是颠覆…

java开发之路——用户管理中心_简单初始化

用户管理中心_简单初始化 (一) 初始化项目1. 使用 Ant Design Pro(现成的管理系统) 进行前端初始化2. 后端初始化三种初始化java项目 (二) 遇到的问题【问题1】Ant design pro页面打不开&#xff0c;一直在budiling控制台出现错误error-./src/components/index.ts【问题2】初始…

Tree-V2 实现 全选、反选

使用场景&#xff1a; 需要一个 tree 树形结构体&#xff0c;但是采用 普通的 tree &#xff0c;在数据量大的时候 会造成 tree 渲染的压力&#xff0c;尤其是在勾选的时候。 element ui plus 中 引入了 “Tree V2 虚拟化树形控件” 具体的内容可以 参考这里 <el-button …

《AI编程类工具之六——CodeWhisperer》

一.简介 官网:AI 代码生成器 – Amazon CodeWhisperer – AWS CodeWhisperer是亚马逊推出的一款实时AI编程助手,它基于机器学习技术,能够分析开发者在集成开发环境(IDE)中的注释和代码,并根据其内容生成多种代码建议。这款编程助手的一大特色是支持自然语言输入,开发者…

基于SSM的物业管理系统(含源码+sql+视频导入教程+文档+PPT)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSM的物业管理系统2拥有三种角色 管理员&#xff1a;用户管理、物业管理、房产信息管理、小区概况管理、开发商管理、收费标准管理、物业公司管理等 物业&#xff1a;住户管理、收费…

如何通过cURL库实现远程控制插座

如何通过cURL库实现远程控制插座呢&#xff1f; 本文描述了使用cURL库调用HTTP接口&#xff0c;实现控制插座&#xff0c;即插即用&#xff0c;先插入插座&#xff0c;再接电器&#xff0c;实现远程控制。 可选用产品&#xff1a;可根据实际场景需求&#xff0c;选择对应的规格…

udp/tcp错误总结

udp tcp——多进程 tcp——多线程 tcp——线程池 tcp——守护进程 &#x1f386;udp  ✨pthread_create 错误总结  ✨LockGuard错误总结  ✨服务端需要写成多线程  ✨客户端也需要写成多线程  ✨多线程调试工具 &#x1f386;tcp  ✨tcp独有调试工具——telnet  ✨Threa…

XGBoost原生接口和Sklearn接口参数详解

XGBoost原生接口和Sklearn接口参数详解 数据科学&#xff1a;Scipy、Scikit-Learn笔记超参数调优&#xff1a;网格搜索&#xff0c;贝叶斯优化&#xff08;optuna&#xff09;详解LightGBM原生接口和Sklearn接口参数详解XGBoost一、Sklearn风格接口xgboost.XGBRegressor参数一般…

基于瞬时频率的语言信号清/浊音判决和高音检测(MATLAB R2021)

语音是由气流激励声道从嘴唇或鼻孔辐射出来而产生的。根据声带是否振动&#xff0c;发音可分为浊音和清音。浊音和清音有明显的区别&#xff0c;浊音具有周期信号的特征&#xff0c;而清音则具有随机噪声的特征&#xff1b;浊音在频域上具有共振峰结构&#xff0c;其能量主要集…

⑤【Shiro】SpringBoot整合Shiro,实现登录认证

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ ⑤【Shiro】SpringBoot整合Shiro&#xff0c;实…

AI助力科研创新与效率双提升:ChatGPT深度科研应用、数据分析及机器学习、AI绘图与高效论文撰写

2022年11月30日&#xff0c;可能将成为一个改变人类历史的日子——美国人工智能开发机构OpenAI推出了聊天机器人ChatGPT3.5&#xff0c;将人工智能的发展推向了一个新的高度。2023年4月&#xff0c;更强版本的ChatGPT4.0上线&#xff0c;文本、语音、图像等多模态交互方式使其在…

计算机网络4——网络层2

文章目录 一、地址解析协议ARP二、IP数据报格式1、IP 数据报首部的固定部分中的各字段2、IP 数据报首部的可变部分 三、IP 层转发分组的过程1、流程2、案例分析3、最长前缀匹配4、分组转发算法5、使用二叉线索查找转发表 一、地址解析协议ARP 在实际应用中&#xff0c;我们经常…

深度学习推理框架汇总

深度学习推理框架汇总 TensorFlow Serving&#xff1a;TensorFlow Serving 是 TensorFlow 的官方模型服务框架&#xff0c;专门用于部署 TensorFlow 模型。它提供了高性能、可扩展、灵活的模型部署和推理服务。 TorchServe&#xff1a;TorchServe 是 PyTorch 官方推出的模型服…

使用Spring Boot双数据源和PageHelper实现无缝分页查询

在开发中&#xff0c;有时我们需要使用多个数据源来访问不同的数据库。而在分页查询时&#xff0c;我们希望能够方便地使用PageHelper插件来处理结果集的分页逻辑。通过结合Spring Boot的双数据源功能和PageHelper的Spring Boot Starter&#xff0c;我们可以实现简单且高效的分…

第一篇【传奇开心果系列】Python深度学习库技术点案例示例:深度解读深度学习在自动驾驶领域的应用

传奇开心果博文系列 系列博文目录Python深度学习库技术点案例示例系列 博文目录前言一、深度学习在自动驾驶方面的应用介绍二、目标检测和识别示例代码三、路况感知示例代码四、行为预测示例代码五、路径规划示例代码六、自动驾驶控制示例代码七、感知融合示例代码八、高精度地…