LeetCode Hard|【460. LFU 缓存】
力扣题目链接
LFU全称是最不经常使用算法(Least Frequently Used),LFU算法的基本思想和所有的缓存算法一样,一定时期内被访问次数最少的页,在将来被访问到的几率也是最小的。
相较于 LRU 算法,LFU 更加注重于使用的频率。 LRU 其实可以看作是频率为 1 的LFU。
从上图中我们可以看到,LFU是根据频率来进行排序,当我们插入的时候,会把新插入的放到链表的尾部,因为新插入的一定没有出现过的,所以频率都会是1,所以会放在最后。
整个算法流程如下:
- 如果A没有出现过,那么就会放在双向链表的最后,依次类推,就会是Z、Y。。C、B、A的顺序放到频率为1的链表中。
- 当我们新插入 A,B,C 那么A,B,C就会到频率为2的链表中
- 如果再次插入A,B那么A,B会在频率为3中。C依旧在2中
- 如果此时已经满了 ,新插入一个的话,我们会把最后一个D移除,并插入 6
整体算法如下:
文章目录
- 自定义类型
- 定义成员变量
- 定义私有成员函数
- 构造函数
- get方法
- put方法
- 总体代码如下
自定义类型
根据题目中的描述,我们除了维护一个键值对之外,还要为这个键值对维护一个计数器:
struct Node {int key, value, freq;Node() : key(0), value(0), freq(1) {}Node(int key, int value) : key(key), value(value), freq(1) {}
};
定义成员变量
很明显,除了 LFUCache 的容量之外,我们还要维护一个最小频率,到时候清除缓存是清除最小频率的最久未使用:
class LFUCache {
private:int capacity_, minFreq_;std::unordered_map<int, Node*> keyNode_; //从键到节点的映射std::unordered_map<int, std::list<Node*>> freqList_; //从频率到节点链表的映射std::unordered_map<Node*, std::list<Node*>::iterator> nodeIter_; //从节点到其在列表中位置的映射
};
定义私有成员函数
这里我们需要一个私有成员函数,也就是更新频率的函数,其实逻辑还是比较好理解的。
void updateFrequency(Node* node) {int freq = node->freq;auto& nodeList = freqList_[freq]; //获取该频率对应的节点链表nodeList.erase(nodeIter_[node]); // 从该链表中删除该节点,因为该节点的频率注定被改变了// 如果当前频率的节点链表为空,删除该频率并更新最小频率if (nodeList.empty()) {freqList_.erase(freq);if (minFreq_ == freq) minFreq_++; //当前删除的频率链表为最小频率时,更新最小频率}//增加节点的频率,并将其插入到新的频率-节点链表的最前面node->freq++;freqList_[node->freq].push_front(node);nodeIter_[node] = freqList_[node->freq].begin(); //记录每个节点在各自链表中的位置}
构造函数
class LFUCache {
private:...
public:LFUCache(int capacity) : capacity_(capacity), minFreq_(0) {}
};
get方法
// 获取指定键的值int get(int key) {if (keyNode_.find(key) == keyNode_.end()) {return -1;} else {Node* node = keyNode_[key];updateFrequency(node);return node->value;}}
put方法
//插入或更新键值对void put(int key, int value) {if (capacity_ == 0) return; //容量为0,直接返回// 更新值、更新频率if (keyNode_.find(key) != keyNode_.end()) {Node* node = keyNode_[key];node->value = value;updateFrequency(node);} else {// 容量已满if (keyNode_.size() == capacity_) {auto& nodeList = freqList_[minFreq_]; //找到最小频率的那个 nodelistNode* node = nodeList.back(); //最小频率的最久未使用节点keyNode_.erase(node->key); //从键到节点的映射中删除该节点nodeIter_.erase(node); // 从节点到其所属位置映射中删除该节点nodeList.pop_back(); //从获取到的频率链表中删除该节点if (nodeList.empty()) freqList_.erase(minFreq_); //如果频率列表为空,删除该频率链表delete node;}//如果缓存未满的情况下,插入新节点并更新相关映射Node* newNode = new Node(key, value);keyNode_[key] = newNode;freqList_[1].push_front(newNode);nodeIter_[newNode] = freqList_[1].begin();minFreq_ = 1; //重置最小频率}}
总体代码如下
struct Node {int key, value, freq;Node() : key(0), value(0), freq(1) {}Node(int key, int value) : key(key), value(value), freq(1) {}
};class LFUCache {
private:int capacity_, minFreq_;std::unordered_map<int, Node*> keyNode_; //从键到节点的映射std::unordered_map<int, std::list<Node*>> freqList_; //从频率到节点链表的映射std::unordered_map<Node*, std::list<Node*>::iterator> nodeIter_; //从节点到其在列表中位置的映射// 无论使用 get 还是 put 方法都会导致节点频率的增加void updateFrequency(Node* node) {int freq = node->freq;auto& nodeList = freqList_[freq]; //获取该频率对应的节点链表nodeList.erase(nodeIter_[node]); // 从该链表中删除该节点,因为该节点的频率注定被改变了// 如果当前频率的节点链表为空,删除该频率并更新最小频率if (nodeList.empty()) {freqList_.erase(freq);if (minFreq_ == freq) minFreq_++; //当前删除的频率链表为最小频率时,更新最小频率}//增加节点的频率,并将其插入到新的频率-节点链表的最前面node->freq++;freqList_[node->freq].push_front(node);nodeIter_[node] = freqList_[node->freq].begin(); //记录每个节点在各自链表中的位置}
public:LFUCache(int capacity) : capacity_(capacity), minFreq_(0) {}int get(int key) {if (keyNode_.find(key) == keyNode_.end()) {return -1;} else {Node* node = keyNode_[key];updateFrequency(node);return node->value;}}void put(int key, int value) {if (capacity_ == 0) return; //容量为0,直接返回// 更新值、更新频率if (keyNode_.find(key) != keyNode_.end()) {Node* node = keyNode_[key];node->value = value;updateFrequency(node);} else {// 容量已满if (keyNode_.size() == capacity_) {auto& nodeList = freqList_[minFreq_]; //找到最小频率的那个 nodelistNode* node = nodeList.back(); //最小频率的最久未使用节点keyNode_.erase(node->key); //从键到节点的映射中删除该节点nodeIter_.erase(node); // 从节点到其所属位置映射中删除该节点nodeList.pop_back(); //从获取到的频率链表中删除该节点if (nodeList.empty()) freqList_.erase(minFreq_); //如果频率列表为空,删除该频率链表delete node;}//如果缓存未满的情况下,插入新节点并更新相关映射Node* newNode = new Node(key, value);keyNode_[key] = newNode;freqList_[1].push_front(newNode);nodeIter_[newNode] = freqList_[1].begin();minFreq_ = 1; //重置最小频率}}
};
相关文章:
LeetCode Hard|【460. LFU 缓存】
力扣题目链接 LFU全称是最不经常使用算法(Least Frequently Used),LFU算法的基本思想和所有的缓存算法一样,一定时期内被访问次数最少的页,在将来被访问到的几率也是最小的。 相较于 LRU 算法,LFU 更加注重…...
积极参与全球能源科技前沿对话,海博思创推动绿色低碳发展
在能源转型与绿色低碳发展的全球浪潮中,国内领先的储能解决方案供应商海博思创以卓越的技术实力和前瞻性的战略眼光,站在了行业变革的前沿。公司不仅在国内外多个重要展会上大放异彩,更通过一系列技术创新与深度合作,为全球能源行…...
[工具]-ffmpeg-笔记
朋友有一个需求,将视频文件转化为音频文件、音频文件获取音频转化为文本文件。 思路:通过ffmpeg转化视频为音频,通过百度ai提供的voice_t_text接口提取语音文本,但是需要将音频分割成1分钟内的pcm编码 ,采样率16000的…...
Android Fragment:详解,结合真实开发场景Navigation
目录 1)Fragment是什么 2)Fragment的应用场景 3)为什么使用Fragment? 4)Fragment如何使用 5)Fragment的生命周期 6)Android开发,建议是多个activity,还是activity结合fragment&…...
JavaWeb中的Servlet
本笔记基于【尚硅谷全新JavaWeb教程,企业主流javaweb技术栈】https://www.bilibili.com/video/BV1UN411x7xe?vd_sourcea91dafe0f846ad7bd19625e392cf76d8总结 Servlet Servlet简介 动态资源和静态资源 静态资源 无需在程序运行时通过代码运行生成的资源,在程序运…...
SpringBoot AOP 简单的权限校验
本篇文章的主要内容是通过AOP切面编程实现简单的权限校验。 书接上回登录与注册功能 我们的用户表里面不是有role(权限)这个字段吗 在JWT令牌的生成中,我们加入了role字段。 那么接下来,我们就可以通过这个字段来实现权限校验。 我这里就很简单&#x…...
Java生成Word->PDF->图片:基于poi-tl 进行word模板渲染
文章目录 引言I Java生成Word、PDF、图片文档获取标签渲染数据生成文档案例II 工具类封装2.1 word 渲染和word 转 pfd2.2 pdf转成一张图片III poi-tl(word模板渲染) 标签简介文本标签{{var}}图片标签表格标签引用标签IV poi-tl提供了类 Configure 来配置常用的设置标签类型前后…...
JVM内存模型笔记
1. 运行时数据区概述 JVM内存布局规定了Java运行过程中的内存申请、分配和管理策略。运行时数据区分为线程私有和线程共享两种。 2. 线程私有内存 程序计数器:存储当前线程执行的字节码指令地址。虚拟机栈:保存方法调用的局部变量和部分结果。本地方法…...
每日一练 - eSight 网管远程告警通知方式
01 真题题目 eSight 网管支持的远程告警通知方式包括:(多选) A.邮件 B.语音 C.短信 D.微信 02 真题答案 AC 03 答案解析 eSight 网管系统支持多种远程告警通知方式,包括邮件和短信。 这些通知方式可以帮助网络管理员及时了解网络设备的状态和告警信息࿰…...
[matlab] 鲸鱼优化算法优化KNN分类器的特征选择
目录 引言 智能优化算法概述 智能优化算法在KNN特征选择中的应用 应用步骤 UCI数据集 鲸鱼优化算法 一、算法背景与原理 二、算法组成与步骤 三、算法特点与优势 四、应用与挑战 代码实现 鲸鱼优化算法 主程序 打印结果 引言 智能优化算法在优化KNN(…...
vscode ssh-remote 疑似内存泄漏问题
vscode ssh-remote疑似内存泄漏问题 系统信息与版本号 版本:1.88.1(通用) 日期:2024-04-10T17:42:52.765Z Electron: 28.2.8 ElectronBuildId: 27744544 Chromium:120.0.6099.291 Node.js:18.18.2 V8&…...
初识自然语言处理NLP
文章目录 1、简介2、自然语言处理的发展简史3、语言学理论句法学(Syntax)语义学(Semantics)语用学(Pragmatics)形态学(Morphology) 4、统计与机器学习方法n-gram 模型隐马尔可夫模型…...
分布式系统架构-微服务架构
一.什么是分布式系统架构 分布式系统架构是指将一个单一的应用程序或服务拆分成多个独立的部分,这些部分可以在不同的计算机、服务器或者地理位置上运行,并通过网络进行通信和协作。分布式系统的设计旨在提高系统的可靠性、可用性和扩展性,同…...
docker搭建内网穿透服务
docker搭建内网穿透服务 frpfrpsfrpc zerotier构建 moon构建 planet查询客户端配置moon方法 nps frp 参考文章:https://blog.csdn.net/weixin_43909881/article/details/126526059 frps docker pull snowdreamtech/frps docker run --restartalways --network ho…...
html+css+js网页设计 体育 金轮健身7个页面
htmlcssjs网页设计 体育 金轮健身7个页面 网页作品代码简单,可使用任意HTML编辑软件(如:Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作)。 获取源码 1&…...
BGP基础简介(一)
AS 是一组运行相同IGP协议的设备组成的网络 AS号: 16bit:64512~65535为私有AS32bit:4200000000~4294967294为私有AS其余都是共有AS,需要向IANA申请 EGP 外部网关协议,bgp的前身,缺点:只发布路由信息,不…...
力扣面试150 反转链表 II 三指针
Problem: 92. 反转链表 II 👨🏫 参考题解 特殊情况 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val…...
GPT-4.o mini
https://share.xuzhugpt.cloud/ GPT-4.o mini 目前免费使用 把上面[chatgpt4o-mini-xuzhu]复制到UserToken的文本框中 点击[个人账户] 测试一下哈,看看: GPT-4.o代码有时候还是有严重错误:好奇怎么来的 上面是我写得,下面是GPT写…...
【C++】优先级队列(容器适配器)
欢迎来到我的Blog,点击关注哦💕 前言 string vector list 这种线性结构是最基础的存储结构,C(STL)container很好的帮助我们数据存储的问题。 容器适配器 介绍 容器适配器是C标准模板库(STL)中…...
docker代理
Dockerd 代理 sudo mkdir -p /etc/systemd/system/docker.service.d sudo touch /etc/systemd/system/docker.service.d/proxy.confproxy.conf [Service] Environment"HTTP_PROXYproxy.example.com:8080/" Environment"HTTPS_PROXYproxy.example.com:8080/&qu…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...
PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...
论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...
面试高频问题
文章目录 🚀 消息队列核心技术揭秘:从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"?性能背后的秘密1.1 顺序写入与零拷贝:性能的双引擎1.2 分区并行:数据的"八车道高速公路"1.3 页缓存与批量处理…...
若依登录用户名和密码加密
/*** 获取公钥:前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...

