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

最近最少使用缓存

        题目:请设计实现一个最近最少使用缓存,要求如下两个操作的时间复杂度都是O(1)。

  • get(key):如果缓存中存在键key,则返回它对应的值;否则返回-1.
  • put(key,value):如果缓存中之前包含键key,则它的值设为value;否则添加键key及对应的value。在添加一个键时,如果缓存容量已满,则在添加新键之前删除最近最少使用的键(缓存中最长时间没有被使用过的元素)。

        Hashmap的get和put方法时间复杂度是O(1),但其不能找出最近最少使用的键。而要想表示一种顺序关系,不难想到可以使用链表,将链尾视为最近最少使用的元素,每次访问一个元素,将该元素移到链头。

        而将元素移到链头之前,应先将节点从原来位置删掉,若仅仅知道待删除节点,是不能知道前驱节点的,故单链表的增删操作复杂度为O (n)。所以我们需使用双向链表。

        用哈希表的键保存key,哈希表的值保存双向链表的节点。

class LRUCache {class DLinkedNode {int key; //初始化keyint value; //初始化value//初始化双向链表前后联系指针DLinkedNode prev;DLinkedNode next;//初始化双向链表public DLinkedNode() {}public DLinkedNode(int _key, int _value) {key = _key;value = _value;}}//创建哈希表HashMap<Integer, DLinkedNode> map = new HashMap<>();//链表当前大小int size;//链表当前容量int capacity;//链表头部尾部节点DLinkedNode head;DLinkedNode tail;public LRUCache(int capacity) {//大小初始化this.size = 0;//容量初始化this.capacity = capacity;//使用伪头部和伪尾部节点head = new DLinkedNode();tail = new DLinkedNode();head.next = tail;tail.prev = head;}public int get(int key) {//在哈希表中找到key所对应的节点DLinkedNode node = map.get(key);//如果这个节点不存在则返回-1if (node == null) {return -1;}//将这个节点移到头部,再返回这个节点所对应的值movetohead(node);return node.value;}public void put(int key, int value) {//在哈希表中找到key所对应的节点DLinkedNode node = map.get(key);//如果这个节点不存在,则创建一个新的节点进行添加if (node == null) {//创建新节点DLinkedNode newnode = new DLinkedNode(key, value);//将节点加入哈希表map.put(key, newnode);//将这个节点添加到双向链表头部addtohead(newnode);//双向链表容量+1size++;//如果容量超过最大容量,则需将双向链表尾部的节点移除if (size > capacity) {//在链表中删去尾部节点,同时哈希表中也移除掉这个节点,并且双向链表容量-1DLinkedNode tail = removetail();map.remove(tail.key);size--;}} else {//如果这个节点存在,则直接修改valuenode.value = value;//将这个节点在双向链表中移到头部movetohead(node);}}//在头部添加节点的方法public void addtohead(DLinkedNode node) {//head为虚拟头结点,由于是双向链表,添加一个节点需要建立四个连接关系node.next = head.next;head.next.prev = node;node.prev = head;head.next = node;}//移除节点方法public void removenode(DLinkedNode node) {//跳过这个节点重新建立双向连接关系node.prev.next = node.next;node.next.prev = node.prev;}//将节点移到头部的方法public void movetohead(DLinkedNode node) {removenode(node);addtohead(node);}//将节点从尾部移除的方法public DLinkedNode removetail() {//尾部的待删除节点即为虚拟尾结点的前一个节点DLinkedNode res = tail.prev;//将这个节点删除removenode(res);return res;}
}

        当然Java中有已经封装好的数据结构LinkedHashmap可以解答,不过不建议。

class LRUCache extends LinkedHashMap<Integer, Integer>{private int capacity;public LRUCache(int capacity) {super(capacity, 0.75F, true);this.capacity = capacity;}public int get(int key) {return super.getOrDefault(key, -1);}public void put(int key, int value) {super.put(key, value);}@Overrideprotected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {return size() > capacity; }
}

相关文章:

  • dify:开源 LLMOps平台。
  • Android Retrofit 封装模版
  • 物体检测算法-R-CNN,SSD,YOLO
  • 苍穹外卖①
  • Unity数据持久化2——XML
  • JavaScript 中的变量声明方式及其应用场景
  • MySQL学习之DQL语句(数据查询语言)
  • MySQL——表的约束
  • 使用Flask ORM进行数据库操作的技术指南
  • 卷积神经网络(CNN)详细介绍及其原理详解
  • 力扣279. 完全平方数
  • 赶紧收藏!2024 年最常见 20道 Redis面试题(四)
  • 《Python编程从入门到实践》day37
  • 小林coding笔记
  • 英语学习笔记24——Give me/us/him/her/them some ...
  • ES6指北【2】—— 箭头函数
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • Bootstrap JS插件Alert源码分析
  • docker-consul
  • Fastjson的基本使用方法大全
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • log4j2输出到kafka
  • Lsb图片隐写
  • Mithril.js 入门介绍
  • MySQL主从复制读写分离及奇怪的问题
  • nfs客户端进程变D,延伸linux的lock
  • 理清楚Vue的结构
  • 区块链分支循环
  • 如何实现 font-size 的响应式
  • 一个6年java程序员的工作感悟,写给还在迷茫的你
  • 用Python写一份独特的元宵节祝福
  • 测评:对于写作的人来说,Markdown是你最好的朋友 ...
  • ​Spring Boot 分片上传文件
  • #include
  • #NOIP 2014# day.1 T2 联合权值
  • (BAT向)Java岗常问高频面试汇总:MyBatis 微服务 Spring 分布式 MySQL等(1)
  • (c语言)strcpy函数用法
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (SpringBoot)第二章:Spring创建和使用
  • (安卓)跳转应用市场APP详情页的方式
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (附源码)ssm考生评分系统 毕业设计 071114
  • (过滤器)Filter和(监听器)listener
  • (剑指Offer)面试题41:和为s的连续正数序列
  • (切换多语言)vantUI+vue-i18n进行国际化配置及新增没有的语言包
  • .MSSQLSERVER 导入导出 命令集--堪称经典,值得借鉴!
  • .NET Core、DNX、DNU、DNVM、MVC6学习资料
  • .NET Core引入性能分析引导优化
  • .Net 路由处理厉害了
  • .net 前台table如何加一列下拉框_如何用Word编辑参考文献
  • .NET 直连SAP HANA数据库
  • .NET 自定义中间件 判断是否存在 AllowAnonymousAttribute 特性 来判断是否需要身份验证
  • .net/c# memcached 获取所有缓存键(keys)
  • .NET/C# 使用反射调用含 ref 或 out 参数的方法
  • .NET成年了,然后呢?