146、LRU缓存-cangjie

embedded/2024/10/31 11:07:29/

题目

146、LRU缓存

思路

  1. 数据结构

    • 使用 HashMap (map) 存储缓存的键值对。键是缓存的键,值是链表节点,可以通过键快速访问。
    • 使用 LinkedList (lists) 来维护缓存的顺序。链表从头到尾表示使用时间,头部是最老的元素,尾部是最近使用的元素。
    • maxSize 是缓存的最大容量。
  2. 初始化

    • 初始化链表和哈希表。在构造函数中,设置最大容量并创建相应的数据结构。
  3. 获取(get)操作

    • 如果键存在于哈希表中:
      • map 中获取对应的链表节点(即存储的键值对)。
      • 读取值,并将对应节点移到链表的尾部(表示最近使用)。
      • 更新哈希表中该键的新位置。
    • 如果键不存在,返回 -1
  4. 插入(put)操作

    • 如果键已经存在:
      • 移除旧节点并在链表中插入新节点(更新为最新的值)。
    • 如果键不存在:
      • 插入新节点到链表尾部。
      • 如果超过最大容量,移除链表头部(最老的元素)和哈希表中对应的键,确保缓存不超过最大容量。

代码

import std.collection.*class LRUCache {var map : HashMap<Int64, LinkedListNode<Array<Int64>>>var lists : LinkedList<Array<Int64>>var maxSize : Int64init(capacity: Int64) {this.lists = LinkedList<Array<Int64>>() // 链表头最老,尾最新// println("init! list size = ${lists.size}")maxSize = capacitythis.map = HashMap<Int64, LinkedListNode<Array<Int64>>>()}func get(key: Int64): Int64 {// println("get in!")if(map.contains(key)){let oldNode = map[key]var val = oldNode.value[1]// println("get node val ${val}")let newNode = lists.append([key,val])lists.remove(oldNode)map.put(key, newNode)return val}return -1}func put(key: Int64, value: Int64): Unit {// println("put in!")if(map.contains(key)){lists.remove(map[key])let node = lists.append([key,value])map.put(key, node)// println("refresh! list size = ${lists.size}")}else{let node = lists.append([key,value])map.put(key, node)// println("put! list size = ${lists.size}")// println("newNode info : ${node.value[0]}, ${node.value[1]}")if(lists.size > maxSize){// println("cache oversize! remove head")map.remove((lists.firstNode()??throw Exception("er")).value[0])lists.remove((lists.firstNode()??throw Exception("er")))// println("remove over! list size = ${lists.size}")}}}
}/*** Your LRUCache object will be instantiated and called as such:* let obj: LRUCache = LRUCache(capacity)* let param_1 = obj.get(key)* obj.put(key,value)*/

复杂度

时间复杂度

  1. get操作

    • 在哈希表中查找键是 O(1) 的时间复杂度。
    • 移动节点在链表中(移除和插入)也是在 O(1) 的时间复杂度。
    • 因此,get 的总时间复杂度是 O(1)
  2. put操作

    • 查找键操作为 O(1)。
    • 移动节点的操作也是 O(1)。
    • 若需移除链表头部元素,时间复杂度为 O(1)。
    • 因此,put 的总时间复杂度也是 O(1)

空间复杂度

  • HashMapLinkedList 都存储相同数量的元素,因此空间复杂度是 O(n),其中 n 是当前缓存中存储的元素数量。
  • 由于只存储活动的缓存项,所以最大空间复杂度为 O(n),与最大容量相同。

遇到的坑

1、为了实现插入后删除最老,需要从ListNode反查key,所以LinkedListNode需要存储kvpair,不能只存一个value
2、双向链表节点获取问题

map.remove((lists.firstNode()??throw Exception("er")).value[0])
lists.remove((lists.firstNode()??throw Exception("er")))

老生常谈了,option类型的返回值函数需要??判断是否抛错误

public func firstNode(): Option<LinkedListNode<T>>

3、初始化问题
不知道为什么this.map = HashMap<Int64, LinkedListNode<Array<Int64>>>(capacity, lists.firstNode()??throw Exception("error"))会要(Int64) ->Tuple, (capacity, lists.firstNode()??throw Exception("error"))这个不已经是tuple类型了嘛

this.map = HashMap<Int64, LinkedListNode<Array<Int64>>>() // ok,size = 0
this.map = HashMap<Int64, LinkedListNode<Array<Int64>>>((capacity, lists.firstNode()??throw Exception("error"))) // ok,但是需要list初始化的时候起一个头节点 例如先lists.append([0,0])
this.map = HashMap<Int64, LinkedListNode<Array<Int64>>>(capacity, lists.firstNode()??throw Exception("error")) // 不ok,报错如下

在这里插入图片描述

结果

cangjie


http://www.ppmy.cn/embedded/133851.html

相关文章

智能扭矩系统Torque在精密制造领域的应用_SunTorque

【大家好&#xff0c;我是唐Sun&#xff0c;唐Sun的唐&#xff0c;唐Sun的Sun。一站式数智工厂解决方案服务商】 在当今高度发达的工业时代&#xff0c;精密制造领域对于产品质量和性能的要求日益严苛。智能扭矩系统作为一项关键技术&#xff0c;正逐渐在这一领域展现出其独特的…

Java设计模式之代理模式(三)

spring和springboot中默认的代理方式 1、在Spring 5.x中AOP默认依旧使用JDK动态代理。 2、SpringBoot 2.x开始&#xff0c;为了解决使用JDK动态代理可能导致的类型转换异常&#xff0c;而使用CGLIB。 3、在SpringBoot 2.x中&#xff0c;如果需要替换使用JDK动态代理可以通过配…

无纸化学习工具:六大在线笔记应用

在数字化时代&#xff0c;在线笔记工具已成为提升学习效率和整理知识点的重要助手&#xff0c;它们使得定期复习变得更加便捷。随着无纸化办公和学习的普及&#xff0c;许多学生开始倾向于使用平板、电脑甚至手机拍摄黑板内容来记录笔记。市场上涌现的在线笔记工具种类繁多&…

基于SSM校园生活电子商城管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;餐厅信息管理&#xff0c;菜品类型管理&#xff0c;闲置物品管理&#xff0c;订单管理&#xff0c;系统管理 用户账号功能包括&#xff1a;系统首页&#xff0c;个人中心&#xf…

论文速读:YOLO-G,用于跨域目标检测的改进YOLO(Plos One 2023)

原文标题&#xff1a;YOLO-G: Improved YOLO for cross-domain object detection 中文标题&#xff1a;YOLO-G&#xff1a;用于跨域目标检测的改进YOLO 论文地址&#xff1a; 百度网盘 请输入提取码 提取码&#xff1a;z8h7 代码地址&#xff1a; GitHub - airy975924806/yolo…

【JAVA基础】什么是泛型? 什么是反射?

什么是泛型? 什么是反射? 什么是泛型?一 , 泛型 (Generics) 概述二 , 泛型的主要功能三 , 泛型的基本概念四 , 泛型的使用场景五 , 泛型的基本步骤六 , 泛型的优缺点七 , 示例代码 什么是反射?一 , 反射 (Reflection) 概述二 , 反射的主要功能1 . 获取类的信息2 . 创建对象…

SAP-ABAP开发-FUNCTION ALV 补充

一、增加表头 1、基本表头 先创建子程序&#xff0c;对表头内表进行赋值&#xff08;表头内表SLIS T LISTHEADER&#xff09;使用函数创建表头 &#xff08;REUSE_ALV_COMMENTARY_WRITE&#xff09;修改ALV调用函数向I_CALLBACK_TOP_OF_PAGE进行传值&#xff0c;传子程序名称或…

.NET内网实战:通过白名单文件反序列化漏洞绕过UAC

01阅读须知 此文所节选自小报童《.NET 内网实战攻防》专栏&#xff0c;主要内容有.NET在各个内网渗透阶段与Windows系统交互的方式和技巧&#xff0c;对内网和后渗透感兴趣的朋友们可以订阅该电子报刊&#xff0c;解锁更多的报刊内容。 02基本介绍 03原理分析 在渗透测试和红…