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

【LeetCode】【算法】146. LRU缓存

LeetCode - 146.LRU缓存

题目描述

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity)以正整数作为容量capacity初始化 LRU 缓存
int get(int key)如果关键字key存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value)如果关键字key已经存在,则变更其数据值value;如果不存在,则向缓存中插入该组key-value 。如果插入操作导致关键字数量超过capacity,则应该逐出最久未使用的关键字。
函数get和put必须以 O(1) 的平均时间复杂度运行。

实现思路

LRU本质就是通过一个队列实现的,对于put函数和get函数,最特别的地方在于访问时需要将访问的节点挪到队尾。

  1. 创建ListNode以实现节点。其中包含int key, int value, ListNode next, ListNode prev(双向指针的实现)
  2. 在LRU类中的属性包括:
    I. 虚拟头尾节点ListNode dummyHead, dummyTail;
    II. HashMap用于以O(1)平均复杂度访问到目标节点Map<Integer, ListNode> map;(如果需要遍历整个链表来找目标节点,就不是O(1)的复杂度了)
    III. int capacity表示链表的容量,这是题目需要指定的
    IV. int listLen用于记录当前链表的长度
  3. 初始化LRU类,就是对上面的这些属性做一个初始化,记得虚拟头尾节点的next属性和prev属性需要相连
  4. put方法思路:
    I. 使用map来检查这个节点是否在链表中;
    ① 如果在链表中,则通过map得到这个节点,将该节点从链表中删除,并给改节点赋予新的值;
    ② 如果不在链表中,又分为listLen>=capacitylistLen<capacity的情况(也就是链表容量是否超过指定容量了)
    情况1:链表当前容量已经达到了指定容量,需要删除最久未访问节点(队头),使用虚拟头结点dummyHead来做删除;根据给定的key和value新建一个节点
    情况2:链表当前容量未达到指定容量,则链表长度++,根据给定的key和value新建一个节点
    II. 利用dummyTail将该节点放到链表的最后,并更新map中的内容
  5. get方法思路:
    I. 使用map来检查这个节点是否在链表中,不在返回-1;
    II. 否则利用map来拿到这个节点,将它从链表中移除;并利用dummyTail将该节点放到链表最后,返回该节点的值

实现代码

class LRUCache {class ListNode{int key;int value;ListNode next;ListNode prev;public ListNode() {}public ListNode(int key, int value) {this.key = key;this.value = value;}}ListNode dummyHead;ListNode dummyTail;Map<Integer, ListNode> map;int capacity;int listLen;public LRUCache(int capacity) {map = new HashMap<>();dummyHead = new ListNode();dummyTail = new ListNode();dummyHead.next = dummyTail;dummyTail.prev = dummyHead;this.capacity = capacity;this.listLen = 0;}public void put(int key, int value) {ListNode listNode = null;// 如果map里面没有这个keyif (!map.containsKey(key)){// 如果长度已经满了,就移除一个if (listLen >= capacity){ListNode removeNode = dummyHead.next;removeNode.next.prev = removeNode.prev;removeNode.prev.next = removeNode.next;map.remove(removeNode.key);} else {listLen++;}// 新增一个listNode = new ListNode(key, value);}// 如果map里有这个keyelse {listNode = map.get(key);// 把这个listNode从链表上删除ListNode prev_node = listNode.prev;ListNode next_node = listNode.next;prev_node.next = next_node;next_node.prev = prev_node;listNode.value = value;}// 把这个listNode弄到后面去ListNode insertPre = dummyTail.prev;insertPre.next = listNode;listNode.prev = insertPre;listNode.next = dummyTail;dummyTail.prev = listNode;map.put(key, listNode);}public int get(int key) {if (!map.containsKey(key)){return -1;} else {int result = map.get(key).value;// 拿到这个Node,移除它ListNode listNode = map.get(key);// 把这个listNode从链表上删除ListNode prev_node = listNode.prev;ListNode next_node = listNode.next;prev_node.next = next_node;next_node.prev = prev_node;// 把这个listNode弄到后面去ListNode insertPre = dummyTail.prev;insertPre.next = listNode;listNode.prev = insertPre;listNode.next = dummyTail;dummyTail.prev = listNode;map.put(key, listNode);return result;}}
}/*** Your LRUCache object will be instantiated and called as such:* LRUCache obj = new LRUCache(capacity);* int param_1 = obj.get(key);* obj.put(key,value);*/

http://www.mrgr.cn/news/66327.html

相关文章:

  • Redis学习:BigKey、缓存双写一致性更新策略和案例
  • (五)Spark大数据开发实战:灵活运用PySpark常用DataFrame API
  • Spring Bean的作用域和生命周期
  • 近期学习前端的心得
  • Elasticsearch 实战应用详解!
  • Kafka 消息丢失如何处理?
  • Python学习笔记-生成器的应用与原理
  • 好看的超清4K视频素材去哪儿找?下载素材资源网站推荐
  • AI大模型重塑软件开发:流程、优势、挑战与展望
  • 「C/C++」C/C++标准库 之 #include<cctype> 字符分类处理库
  • 牛客周赛 66 F 小苯的字符提前
  • 进程的调度(超详细解读)
  • Day 49 || 1143.最长公共子序列、1035.不相交的线、 53. 最大子序和 、392.判断子序列
  • Java入门(8)--反射机制
  • 零基础学习Spring AI Java AI SpringBoot AI调用大模型OpenAi Ollama集成大模型
  • HarmonyOS开发 - Ability往页面(Pages)中传递数据
  • 年薪平均几十万?!哪些行业的软件测试工程师需求量大,前景好?
  • ubuntu工具 -- ubuntu服务器临时没有网络,急需联网下载东西怎么办? 使用手机提供网络
  • @ApiOperation(“修改帐号状态“)详细解释一下以上代码
  • 视频监控接入平台功能:视频平台系统的硬件性能直观显示和系统软件运行情况和状态显示
  • 【初阶数据结构篇】链式结构二叉树(续)
  • vue组件在项目中的常用业务逻辑(3)
  • 11.5 dmy NOIP模拟赛DAY4 总结
  • operator[ ]和迭代器,auto,for流,reserve
  • MySQL初学之旅(1)配置与基础操作
  • 数据库基础(4) . 数据库结构