当前位置: 首页 > 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.xdnf.cn/news/1098469.html

相关文章:

  • 【笔记分享】集合的基数、群、环、域
  • QT解析文本框数据——概述
  • 实现一个点击输入框可以弹出的数字软键盘控件 qt 5.12
  • 文件系统子系统 · 核心问题问答精要
  • 【性能测试】jmeter+Linux环境部署和分布式压测,一篇打通...
  • 动态规划疑惑总结
  • Ajax之核心语法详解
  • OpenCV探索之旅:多尺度视觉与形状的灵魂--图像金字塔与轮廓分析
  • 安全访问云端内部应用:用frp的stcp功能解决SSH转发的痛点
  • 【Nginx】Nginx 安装与 Sticky 模块配置
  • 使用Docker将Python项目部署到云端的完整指南
  • 网络安全(初级)(1)
  • 显卡GPU的架构和工作原理
  • QT Android 如何打包大文件到目录下?
  • Android ViewBinding 使用与封装教程​​
  • 【数据结构与算法】数据结构初阶:动态顺序表各种方法(接口函数)复盘与整理
  • 模块三:现代C++工程实践(4篇)第二篇《性能调优:Profile驱动优化与汇编级分析》
  • uniapp滚动组件, HuimayunScroll:高性能移动端滚动组件的设计与实现
  • 深入理解oracle ADG和RAC
  • 【大模型推理论文阅读】Enhancing Latent Computation in Transformerswith Latent Tokens
  • 毫米波雷达守护银发安全:七彩喜跌倒检测仪重构居家养老防线
  • 无人机抗风模块运行与技术难点分析
  • AI 智能体:开启自动化协作新时代
  • 浪潮CD1000-移动云电脑-RK3528芯片-2+32G-开启ADB ROOT破解教程
  • UE5源码模块解析与架构学习
  • Spring Boot 3.4 :@Fallback 注解 - 让微服务容错更简单
  • 大健康IP如何借“合规创新”抢占行业新风口|创客匠人
  • 创始人IP如何进阶?三次关键突破实现高效转化
  • Windows 11 安装过程中跳过微软账户创建本地账户
  • TCP传输控制层协议深入理解