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

LFU 缓存

题目链接

LFU 缓存

题目描述


注意点

  • 1 <= capacity <= 10^4
  • 0 <= key <= 10^5
  • 0 <= value <= 10^9
  • 对缓存中的键执行 get 或 put 操作,使用计数器的值将会递增
  • 当缓存达到其容量 capacity 时,则应该在插入新项之前,移除最不经常使用的项
  • 函数 get 和 put 必须以 O(1) 的平均时间复杂度运行

解答思路

  • 创建Node双向链表节点类,其中包含freq,key,value,prev指针,next指针
  • 两个Map,kvMap存储键值对,freqMap存储频率以及对应频率的链表头尾节点,capacity存储容量,minFreq存储最小调用频率
  • 做get()操作时,如果key无相应节点,直接返回-1;如果有相应节点,则其频率要加一,要从原频率链表中移除该节点,并将该节点加入到新频率的链表中,还要注意更新minFreq的值
  • 做put()操作时
    • 如果key有相应节点,则取出原有节点,将原有节点取出,将其频率加一,从原频率链表中移除该节点,并将该节点加入到新频率的链表中,还要注意更新minFreq的值
    • 如果key无相应节点,则需要新建一个节点,写入key,value,freq为1,再将该节点加入到kvMap和freqMap对应频率链表中,还要判断此时kvMap是否已满,如果节点过多还要移除最不经常使用的节点,也就是最低频率minFreq对应链表中的第一个节点,还要注意更新minFreq的值为1

代码

class LFUCache {// 最小调用频率int minFreq;// 容量int capacity;// key->key,value->对应节点Map<Integer, Node> kvMap;// key->使用频率,value->对应链表的头尾节点Map<Integer, Node[]> freqMap;public LFUCache(int capacity) {minFreq = 0;this.capacity = capacity;kvMap = new HashMap<>(capacity);freqMap = new HashMap<>();}public int get(int key) {if (kvMap.get(key) == null) {return -1;}Node node = kvMap.get(key);// 当前节点是最低频率且此时最低频率链表只有该节点,最低频率增加if (node.freq == minFreq && node.prev.prev == null && node.next.next == null) {minFreq++;}// 频率加一node.freq++;// 从旧频率对应链表删除deleteNode(node);// 插入到新频率链表尾部if (freqMap.get(node.freq) == null) {initFreqMap(node.freq);}addTail(node, freqMap.get(node.freq)[1]);return node.value;}public void put(int key, int value) {Node node = new Node();if (kvMap.get(key) != null) {node = kvMap.get(key);// 当前节点是最低频率且此时最低频率只有该节点,最低频率增加if (node.freq == minFreq && node.prev.prev == null && node.next.next == null) {minFreq++;}// 频率加一node.freq++;node.value = value;// 从旧频率对应链表删除deleteNode(node);} else {// 超出容量,移除最小频率的节点if (capacity == 0) {Node head = freqMap.get(minFreq)[0];kvMap.remove(head.next.key);deleteNode(head.next);capacity = 1;}node.freq = 1;node.key = key;node.value = value;kvMap.put(key, node);minFreq = 1;capacity--;}if (freqMap.get(node.freq) == null) {initFreqMap(node.freq);}// 插入到新频率链表尾部addTail(node, freqMap.get(node.freq)[1]);}public void initFreqMap(int freq) {Node head = new Node();Node tail = new Node();head.next = tail;tail.prev = head;Node[] arr = new Node[] {head, tail};freqMap.put(freq, arr);}public void deleteNode(Node node) {Node prevNode = node.prev;Node nextNode = node.next;prevNode.next = nextNode;nextNode.prev = prevNode;node.prev = null;node.next = null;}public void addTail(Node node, Node tail) {Node prevNode = tail.prev;prevNode.next = node;node.prev = prevNode;node.next = tail;tail.prev = node;}
}class Node {int freq;int key;int value;Node prev;Node next;
}

关键点

  • 注意更新minFreq的值
  • 双向链表的相关操作
  • 容量满时插入节点需要对使用频率最低的节点做删除操作
http://www.lryc.cn/news/584409.html

相关文章:

  • iOS APP混合开发性能测试怎么做?页面卡顿、通信异常的工具组合实战
  • iOS Widget 开发-7:TimelineProvider 机制全解析:构建未来时间线
  • 快速上手ASP .NET Core 8与MongoDB整合
  • Mac 电脑crontab执行定时任务【Python 实战】
  • 【保姆级喂饭教程】idea中安装Conventional Commit插件
  • Wsl/InstallDistro/Service/RegisterDistro/CreateVm/HCS/E_INVALIDARG
  • Android ViewBinding 使用与封装教程​​
  • Flutter 与 Android 的互通几种方式
  • 第35周—————糖尿病预测模型优化探索
  • 灰度发布过程中的异常处理
  • frp内网穿透下创建FTP(解决FTP“服务器回应不可路由的地址。使用服务器地址替代”错误)
  • Vue响应式原理五:响应式-自动收集依赖
  • 【Action帧简要分析】
  • 实验作业1+整理笔记截图
  • LLM 微调:从数据到部署的全流程实践与经验分享
  • TradePort 借助 Walrus 构建更高级的 NFT 市场
  • FPGA设计思想与验证方法学系列学习笔记001
  • 基于“SRP模型+”多技术融合在生态环境脆弱性评价模型构建、时空格局演变分析与RSEI 指数的生态质量评价及拓展应用
  • upload-labs靶场通关详解:第20关 /.绕过
  • 【计算机网络】HTTP1.0 HTTP1.1 HTTP2.0 QUIC HTTP3 究极总结
  • QT解析文本框数据——概述
  • 中国成人急性髓系白血病(非M3)诊疗指南(2021年版)
  • upload-labs靶场通关详解:第21关 数组绕过
  • Mysql分片:一致性哈希算法
  • 【Python】基于Python提取图片验证码
  • QTextCodec的功能及其在Qt5及Qt6中的演变
  • Qt Creator控件及其用途详细总结
  • Spring for Apache Pulsar->Reactive Support->Message Production
  • 生产环境CI/CD流水线构建与优化实践指南
  • 访问Windows服务器备份SQL SERVER数据库