面试算法31:最近最少使用缓存
题目
请设计实现一个最近最少使用(Least Recently Used,LRU)缓存,要求如下两个操作的时间复杂度都是O(1)。
- get(key):如果缓存中存在键key,则返回它对应的值;否则返回-1。
- put(key,value):如果缓存中之前包含键key,则它的值设为value;否则添加键key及对应的值value。在添加一个键时,如果缓存容量已经满了,则在添加新键之前删除最近最少使用的键(缓存中最长时间没有被使用过的元素)。
分析
哈希表HashMap的get操作和put操作的时间复杂度都是O(1),但普通的哈希表无法找出最近最少使用的键,因此,需要在哈希表的基础上进行改进。
由于需要知道缓存中最近最少使用的元素,因此可以把存入的元素按照访问的先后顺序存入链表中。每次访问一个元素(无论是通过get操作还是通过put操作),该元素都被移到链表的尾部。这样,位于链表头部的元素就是最近最少使用的。
下面考虑如何实现把一个节点移到链表的尾部。这实际上包含两个步骤,首先要把节点从原来的位置删除,然后把它添加到链表的尾部。需要注意的是,在链表中删除一个节点,实际上是把它的前一个节点的next指针指向它的下一个节点。如果这个链表是单向链表,那么找到一个节点的前一个节点需要从链表的头节点开始顺序扫描每个节点,也就需要O(n)的时间。
为了快速找到一个节点的前一个节点从而实现用O(1)的时间删除一个节点,可以用双向链表来存储缓存中的元素。在双向链表中查找一个节点的前一个节点只需要顺着prev指针向前走一步,时间复杂度为O(1)。
因此,设计最近最少使用缓存需要结合哈希表和双向链表的特点。哈希表的键就是缓存的键,哈希表的值为双向链表中的节点,每个节点都是一组键与值的数对。

解
public class Test {public static void main(String[] args) {LRUCache lruCache = new LRUCache(4);lruCache.put(1,1);lruCache.put(2,2);lruCache.put(3,3);lruCache.put(4,4);ListNode node1 = lruCache.head;while (node1 != null){System.out.println(node1.value);node1 = node1.next;}System.out.println("-------------------------");lruCache.get(2);ListNode node2 = lruCache.head;while (node2 != null){System.out.println(node2.value);node2 = node2.next;}System.out.println("-------------------------");lruCache.put(1,8);ListNode node3 = lruCache.head;while (node3 != null){System.out.println(node3.value);node3 = node3.next;}System.out.println("-------------------------");lruCache.put(5,5);ListNode node4 = lruCache.head;while (node4 != null){System.out.println(node4.value);node4 = node4.next;}}static class ListNode{public int key;public int value;public ListNode next;public ListNode prev;public ListNode(int k,int v){key = k;value = v;}}static class LRUCache{private ListNode head;private ListNode tail;private Map<Integer,ListNode> map;int capacity;public LRUCache(int cap){map = new HashMap<>();head = new ListNode(-1,-1);tail = new ListNode(-1,-1);head.next = tail;tail.prev = head;capacity = cap;}public int get(int key){ListNode node = map.get(key);if (node == null){return -1;}moveToTail(node,node.value);return node.value;}public void put(int key,int value){if (map.containsKey(key)){moveToTail(map.get(key),value);}else {if (map.size() == capacity){ListNode toBeDeleted = head.next;deleteNode(toBeDeleted);map.remove(toBeDeleted.key);}ListNode node = new ListNode(key,value);intsertToTail(node);map.put(key,node);}}private void moveToTail(ListNode node,int newValue){deleteNode(node);node.value = newValue;intsertToTail(node);}private void deleteNode(ListNode node){node.prev.next = node.next;node.next.prev = node.prev;}private void intsertToTail(ListNode node){tail.prev.next = node;node.prev = tail.prev;node.next = tail;tail.prev = node;}}
}
相关文章:
面试算法31:最近最少使用缓存
题目 请设计实现一个最近最少使用(Least Recently Used,LRU)缓存,要求如下两个操作的时间复杂度都是O(1)。 get(key):如果缓存中存在键key,则返回它对应的值…...
如何处理前端SEO(搜索引擎优化)?
聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…...
Leetcode—2529.正整数和负整数的最大计数【简单】
2023每日刷题(四) Leetcode—2529.正整数和负整数的最大计数 遍历法实现代码 int maximumCount(int* nums, int numsSize){int i;int neg 0, pos 0;for(i 0; i < numsSize; i) {if(nums[i] < 0) {neg;}if(nums[i] > 0) {pos;}}return (neg…...
数据结构-- 并查集
0. 引入 并查集是来解决等价问题的数据结构。 离散数学中的二元关系。 等价关系需满足自反性、对称性、传递性。 a ∈ S , a R a a R b & b R a a R b ∩ b R c > a R c a \in S, aRa \\ aRb \& bRa \\ aRb \cap bRc >aRc a∈S,aRaaRb&bRaaRb∩bRc>a…...
优维产品最佳实践第12期:IT资源管理首页丰富
背 景 当我们进入平台后,默认跳转至IT资源管理首页,因此该页面的优化与丰富将极大的提高平台使用者的体验和效率。优化后的首页可以更好地展示常用模型、小产品、外部系统、以及保存的所有关系查询和快速查询条件,使用户能够更快捷、方便…...
【Nginx34】Nginx学习:安全链接、范围分片以及请求分流模块
Nginx学习:安全链接、范围分片以及请求分流模块 又迎来新的模块了,今天的内容不多,但我们都进行了详细的测试,所以可能看起来会多一点哦。这三个模块之前也从来都没用过,但是通过学习之后发现,貌似还都挺有…...
PO模式在selenium自动化测试框架的优势
大家都知道po模式可以提高代码的可读性和减少了代码的重复,但是相对的缺点还有,今天通过本文一起学习下PO模式在selenium自动化测试框架的优势,需要的朋友可以参考下 PO模式简介 1.什么是PO模式 PO模型是:Page Object Model的简写 页面对象…...
Java操作Elasticsearch(新增数据)
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...
Android中级——MVVM
MVVM MVVM是什么?MVVM实现前提ModelViewModelView MVVM是什么? Model-View-ViewMode架构,可看作MVP改进版,将此前Presenter的逻辑操作交给ViewMode中的Binder去处理 Mode:封装数据存储及相关操作逻辑,与MV…...
AIGC:引领人工智能和游戏产业融合的里程碑
目录 引言: 一、AIGC简介 二、AIGC的意义和作用 三、AIGC的未来展望 四、AIGC的影响和成果 五、结论 引言: 人工智能技术的快速发展在过去几年中引起了全球范围内的广泛关注和热议。其中,AIGC(Artificial Intelligence and G…...
ubuntu安装rust教程
参考【Rust】Linux上安装Rust开发环境 sudo apt-get install curl# 注意,不开代理很可能下不到,一直报403 export RUSTUP_DIST_SERVERhttps://mirrors.ustc.edu.cn/rust-static export RUSTUP_UPDATE_ROOThttps://mirrors.ustc.edu.cn/rust-static/rustu…...
iOS UIWebView与WKWebView 那些事
一、前言介绍 UIWebView 是 iOS 2 中推出的网页容器,UIWebView是最占内存的控件;直到 iOS 8 以后,苹果推出了 WebKit 框架,其中 WKWebView 正式被推出来接替 UIWebView 的位置;iOS 12 中,苹果正式弃用 UIWebView,要求开发者用 WKWebView 全面替换 UIWebView,apple 官方…...
wps/word 之 word中的两个表格 如何合并成为一个表格(已解决)
第一步:新建两个表格: 如何实现上面的两个表格合并呢? 分别选定每个表格,然后鼠标右键---》表格属性 在表格属性中的 表格---》选择 无文字环绕。 第二个表格按照同样的方法 设置 无文字环绕。 然后将中的文本行删去即可以了。选…...
02HTML功能元素
1.功能元素 1.1.列表标签 列表标签的作用: 给一堆数据添加列表语义, 也就是告诉搜索引擎告诉浏览器这一堆数据是一个整体 - HTML中列表标签的分类 无序列表(最多)(unordered list) 有序列表(最少)(ordered list) 定义列表(其次)(definition list) 1.1.1.无序列…...
并发编程-延时队列DelayQueue
数据结构学习网站: Data Structure Visualization 思维导图 DelayQueue (延时队列) DelayQueue 是一个支持延时获取元素的阻塞队列 , 内部采用优先队列 PriorityQueue 存储元素,同时元素必须实现 Delayed 接口&#x…...
Python之哈希表-遍历和有序性
Python之哈希表-遍历和有序性 有序性 字典元素是按照key的hash值无序存储的。 但是,有时候我们却需要一个有序的元素顺序,Python 3.6之前,使用OrderedDict类可以做到,3.6开 始dict自身支持。 d1 {b:33, c:True, d:[1], f:234…...
Oracle数据库完整卸载的完整步骤
时间:2023-03-15来源:系统城装机大师作者:佚名 1、停止所有Oracle服务 进入计算机管理,在服务中,找到oracle开头的所有服务,右击选择停止。 快捷键:ctrlshiftesc打开任务管理器 文章来源 Or…...
HP OfficeJet Pro 8020 如何更换碳粉盒
环境: HP OfficeJet Pro 8020 问题描述: HP OfficeJet Pro 8020 如何更换碳粉盒 解决方案: 更换碳粉盒 更换所有墨水不足的碳粉盒或空碳粉盒。 1.打开前挡盖,然后提起碳粉盒检修门。 打开打印机门 2.等待笔架停止后再继续操作…...
【Javascript】基础数据类型
目录 基础数据类型 1.number 字面量声明 数字对象方式声明 整数判断 指定返回小数位数 NaN-表示非数字值 浮点精度 解决误差 String 字面量声明 数字对象声明 连接运算符 获取长度 大小写转换 转换成大写 转换成小写 编辑 移除空白 获取单字符 编辑 截…...
【C语言】进阶——程序编译
目录 一:🔒程序环境 程序的翻译环境和执行环境 💡1.1翻译环境 预编译阶段: 编译阶段: 汇编阶段: 链接阶段: 💡1.2运行环境 二:🔒预处理详解 &…...
别再为ModelSim仿真头疼了!手把手教你用Quartus 13.0搭建VHDL七段译码器(附完整库文件配置)
Quartus 13.0与ModelSim仿真全攻略:从零搭建VHDL七段译码器 刚接触FPGA开发的朋友们,是否曾在Quartus和ModelSim的配合使用中遇到过各种"玄学"问题?明明代码编译通过了,仿真时却一片空白;或者波形文件加载了…...
精密机械制造工厂研发部门使用SolidWorks和ug,三维设计云桌面如何选择?
在精密机械制造工厂研发部门使用SolidWorks和UG进行三维设计时,云桌面的选择应聚焦于硬件性能、资源管理、数据安全、协同效率及成本控制五大核心维度。以下是一个基于云飞云智能共享云桌面的推荐方案,该方案已成功应用于多家精密机械制造企业࿰…...
零代码RPA神器taskt:如何用免费开源工具实现跨平台自动化革命
零代码RPA神器taskt:如何用免费开源工具实现跨平台自动化革命 【免费下载链接】taskt taskt (pronounced tasked and formely sharpRPA) is free and open-source robotic process automation (rpa) built in C# powered by the .NET Framework 项目地址: https:/…...
别再死记硬背了!用FreeSWITCH实战理解PSTN与VoIP核心概念(信令/媒体/交换)
从FreeSWITCH实战出发:用配置与日志理解PSTN与VoIP核心架构 在通信技术领域,PSTN与VoIP的理论概念常常让初学者感到抽象难懂。那些关于信令、媒体流、交换方式的教科书定义,往往需要反复背诵却依然难以形成直观认知。而FreeSWITCH作为一款开源…...
麒麟KYLINOS软件安装全攻略:从新手到高手的五种进阶路径
1. 初识麒麟KYLINOS:从Windows/macOS迁移者的第一课 第一次打开麒麟KYLINOS的桌面环境,那种既熟悉又陌生的感觉让我想起十年前第一次用Linux的场景。作为从Windows转战过来的用户,最迫切的问题就是:软件怎么装?在Windo…...
跨平台游戏模组下载指南:WorkshopDL终极解决方案
跨平台游戏模组下载指南:WorkshopDL终极解决方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 还在为GOG或Epic平台购买的游戏无法使用Steam创意工坊模组而烦恼吗…...
2026在校大学生可以考哪些大数据专业证书?
新学期开始后,关于“大学期间该准备哪些证书”的讨论总能在校园里听到。对于大数据相关专业的在校生而言,面对技术快速迭代的行业环境,如何利用课余时间提前做些准备,用证书为自己的学习成果做个阶段性总结,成为不少人…...
告别U盘和光盘:用iSCSI虚拟硬盘给服务器装Kylin V10 SP1(保姆级图文)
无盘化革命:基于iSCSI的麒麟V10 SP1服务器高效部署指南 在数据中心运维和服务器管理的日常工作中,系统部署效率往往成为制约整体工作流程的关键瓶颈。传统的光盘或U盘安装方式不仅耗时费力,在面对批量部署需求时更是捉襟见肘。本文将介绍一种…...
免费-开源的API接口集合,用于你的练手项目
在开发练手项目时,获取真实数据往往是一个难题。无论是学习前端框架、后端开发,还是测试移动应用,免费且开源的API接口集合都能为你提供便捷的数据支持。这些API覆盖了天气、金融、社交、新闻等多个领域,无需注册或付费即可调用&a…...
SAML单点登录实战:一次配置,搞定Okta和SAP SuccessFactors(SF平台)
SAML单点登录实战:跨平台统一身份认证解决方案 想象一下,当你每天需要登录十几个不同的业务系统时,记住一堆用户名密码的烦恼。更糟的是,作为企业IT管理员,还要处理员工频繁的密码重置请求。这正是为什么越来越多的企业…...
