【leetcode】缓存淘汰策略题目总结

146. LRU 缓存

我们使用了一个双向链表cache来存储数据,同时使用一个哈希表hash_map来映射键和链表节点的迭代器。当调用get(key)函数时,我们首先检查hash_map中是否存在该key,如果存在则将之前位置移到链表头部并返回值;当调用put(key, value)函数时,我们先检查hash_map中是否存在该key,存在的话将该节点从链表中删除,不管存在与否都需要考虑是否需要删除旧数据(缓存已满的情况)。

class LRUCache {
private:int _capacity;list<pair<int, int>> _cache;unordered_map<int, list<pair<int, int>>::iterator> _hashmap;public:LRUCache(int capacity) {_capacity = capacity;}int get(int key) {if (_hashmap.find(key) == _hashmap.end()) {return -1;}auto iter = _hashmap[key];int value = iter->second;_cache.erase(iter);_cache.push_front({key, value});_hashmap[key] = _cache.begin();return value;}void put(int key, int value) {if (_hashmap.find(key) != _hashmap.end()) {auto iter = _hashmap[key];_cache.erase(iter);} else if (_cache.size() >= _capacity) {auto hashKey = _cache.back().first;_hashmap.erase(hashKey);_cache.pop_back();}_cache.push_front({key, value});_hashmap[key] = _cache.begin();}
};/*** 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);*/

460. LFU 缓存

我们定义两个哈希表,

第一个 freq_table 以频率 freq 为索引,每个索引存放一个双向链表,这个链表里存放所有使用频率为 freq 的缓存,缓存里存放三个信息,分别为键 key,值 value,以及使用频率 freq。

第二个 key_table 以键值 key 为索引,每个索引存放对应缓存在 freq_table 中链表里的内存地址,这样我们就能利用两个哈希表来使得两个操作的时间复杂度均为 O(1)。

同时需要记录一个当前缓存最少使用的频率 minFreq,这是为了删除操作服务的。

struct Node
{int key;int val;int freq;Node(int _key, int _val, int _freq) : key(_key), val(_val), freq(_freq) {}
};class LFUCache {
private:int capacity;int minfreq;unordered_map<int, list<Node>> freq_table;unordered_map<int, list<Node>::iterator> key_table;public:LFUCache(int _capacity) {minfreq = 0;capacity = _capacity;key_table.clear();freq_table.clear();}int get(int key) {// 啥也没有if (capacity == 0) {return -1; }// 没有这个keyif (!key_table.count(key)) {return -1;}auto iter = key_table[key];int val  = iter->val;int freq = iter->freq;//查到删除旧的,增加新的freq_table[freq].erase(iter);//中间要判断一下此freq的链表是不是空了if (freq_table[freq].size() == 0) {//删除freq_table.erase(freq);//更新 minfreqif(minfreq == freq) minfreq += 1;}//插入新的freq_table[freq + 1].push_front(Node(key, val, freq + 1));key_table[key] = freq_table[freq + 1].begin();return val;}void put(int key, int value) {// 啥也没有if (capacity == 0) {return; }// 没有的话,加进去if (!key_table.count(key)){// 存储key的数量满了if (key_table.size() == capacity) {// 删掉频率最小的最早使用的auto node = freq_table[minfreq].back();int k = node.key;key_table.erase(k);freq_table[minfreq].pop_back();// 同样,该链空了,删除if (freq_table[minfreq].size() == 0) {freq_table.erase(minfreq);}}// 插入          freq_table[1].push_front(Node(key, value, 1));key_table[key] = freq_table[1].begin();minfreq = 1; //注意这里要更新minfreq,容易出现错误} else {//存在// 更新// 先删,后频率增加,插入auto node = key_table[key];int freq = node->freq;freq_table[freq].erase(node);// 同样链空了,删除if(freq_table[freq].size() == 0){freq_table.erase(freq);if (minfreq == freq) {minfreq += 1;}}// 插入freq_table[freq + 1].push_front(Node(key, value, freq + 1));key_table[key] = freq_table[freq + 1].begin();}}
};
/*** Your LFUCache object will be instantiated and called as such:* LFUCache* obj = new LFUCache(capacity);* int param_1 = obj->get(key);* obj->put(key,value);*/

FIFO 缓存

先进先出,明显使用哈希+队列

#include <iostream>
#include <queue>
#include <unordered_map>class FIFOCache {
private:std::queue<int> fifoQueue; // 存放keystd::unordered_map<int, int> cache; // 存放key-valueint capacity;public:FIFOCache(int capacity) : capacity(capacity) {}int get(int key) {if (cache.find(key) != cache.end()) {return cache[key];}return -1;}void put(int key, int value) {if (cache.size() >= capacity) {int keyToRemove = fifoQueue.front();fifoQueue.pop();cache.erase(keyToRemove);}cache[key] = value;fifoQueue.push(key);}
};int main() {FIFOCache cache(2);cache.put(1, 1);cache.put(2, 2);std::cout << cache.get(1) << std::endl; // 输出:1cache.put(3, 3);std::cout << cache.get(2) << std::endl; // 输出:-1,因为元素2被淘汰了return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/831337.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

每日OJ题_DFS爆搜深搜回溯剪枝⑧_力扣980. 不同路径 III

目录 力扣980. 不同路径 III 解析代码 力扣980. 不同路径 III 980. 不同路径 III 难度 困难 在二维网格 grid 上&#xff0c;有 4 种类型的方格&#xff1a; 1 表示起始方格。且只有一个起始方格。2 表示结束方格&#xff0c;且只有一个结束方格。0 表示我们可以走过的空…

React 第十五章 Ref

React ref 是 React 中一个用于访问组件中 DOM 元素或者类实例的方式。它允许我们直接操作 DOM&#xff0c;而不需要通过 state 或 props 来更新组件。 过时 API&#xff1a;String 类型的 Refs 在最最早期的时候&#xff0c;React 中 Ref 的用法非常简单&#xff0c;类似于 …

Docker consul 的容器服务更新与发现

目录 一. consul 的相关知识 1 什么是注册与发现 2. 什么是 consul 3. zookeeper 和 consul 的区别 二. consul 部署 1. consul 服务器 2. registrator 服务器 三. consul-template 1. consul-template 的作用 2. consul-template 的具体部署运用 2.1 准备 templa…

Deep Learning Part Five RNNLM的学习和评价-24.4.30

准备好RNNLM所需要的层&#xff0c;我们现在来实现RNNLM&#xff0c;并对其进行训练&#xff0c;然后再评价一下它的结果的。 5.5.1 RNNLM的实现 这里我们将RNNLM使用的网络实现为SimpleRnnlm类&#xff0c;其层结构如下&#xff1a; 如图 5-30 所示&#xff0c;SimpleRnnlm …

设计模式: 工厂模式

工厂模式&#xff08;Factory Pattern&#xff09;是 Java 中最常用的设计模式之一&#xff0c;这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。 工厂模式提供了一种创建对象的方式&#xff0c;而无需指定要创建的具体类。 工厂模式属于创建型…

我的毕业实习经历

我的毕业实习经历 前言求职之路成为社畜重获自由结语 前言 这篇博客原本我想以实习生找工作踩坑指南&#xff1a;我的毕业实习经历为文章标题的&#xff0c;原因是跟我前面发布的一篇博客《实习生找工作踩坑指南&#xff1a;租房篇》做一个呼应收尾&#xff0c;奈何标题略显臃肿…

【Oracle】常用命令汇总

本文基于黑马程序员文档做的二次总结&#xff0c;如有侵权&#xff0c;请联系本人删除。 文章目录 字段定义创建表空间创建用户用户赋权创建表表增加字段表更改字段类型表字段重命名表删除字段删除表 记录的增删改表插入记录表修改记录表删除记录 导入导出数据库导出数据库全部…

MongoDB聚合运算符:$sum

MongoDB聚合运算符&#xff1a;$sum 文章目录 MongoDB聚合运算符&#xff1a;$sum语法使用返回的数据类型非数值或缺失字段的处理数组操作数 举例应用于$group阶段应用于$project阶段应用于$setWindowFields阶段 $sum聚合运算符返回数值的合计值&#xff0c;计算式 $sum会忽略…

免费分享一套SpringBoot+Vue在线考试系统(优质版),帅呆了~~

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue在线考试系统(优质版)&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue在线考试系统(优质版) Java毕业设计_哔哩哔哩_bilibili【免费】SpringBootVue在线考试系统(优质版) Java毕…

C++奇迹之旅:C++内存管理的机制(进阶篇)

文章目录 &#x1f4dd;new和delete操作自定义类型&#x1f320; operator new与operator delete函数&#x1f309;operator new与operator delete函数 &#x1f320;new和delete的实现原理&#x1f309;内置类型&#x1f309;自定义类型 &#x1f320;定位new表达式(placement…

KCF算法的优缺点是什么

KCF算法&#xff08;Kernelized Correlation Filters&#xff09;是一种用于目标跟踪的算法&#xff0c;它结合了核技巧和相关滤波器的思想&#xff0c;可以在视频中跟踪运动目标。以下是KCF算法的主要优缺点&#xff1a; 优点&#xff1a; 速度快&#xff1a;KCF算法使用离散…

Python 全栈体系【四阶】(三十八)

第五章 深度学习 八、目标检测 3. 目标检测模型 3.2 YOLO 系列 3.2.1 YOLOv1&#xff08;2016&#xff09; 3.2.1.1 基本思想 YOLO&#xff08;You Only Look Once &#xff09;是继 RCNN&#xff0c;fast-RCNN 和 faster-RCNN 之后&#xff0c;Ross Girshick 针对 DL 目…

【牛客网】值周

原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 差分。 因为l<100000000,所以数组开1e8。 唯一需要注意的点就是前面给b[0]单独赋值为1&#xff08;因为如果在循环中给b[0]赋值&…

Json高效处理方法

一、参考我之前的博客,Delphi可以很方便的把类和结构体转换成JSON数据,但是数据量大了,就会非常之慢,1万条数据需要20秒左右。如果引用Serializers单元,那么100万数据只需要4秒左右,每秒处理20万+,速度还是很快的。 二、写一个简单的类  TPeople = class private …

Docker Compose如何安装

Docker Compose的安装通常依赖于你的操作系统。以下是在不同操作系统中安装Docker Compose的方法&#xff1a; Linux 系统 //下载最新版本的Docker Compose sudo curl -L "https://github.com/docker/compose/releases/download/v2.5.1/docker-compose-$(uname -s)-$(un…

算法训练营第十天 | LeetCode 232 用栈实现队列、LeetCode 225 用队列实现栈

栈的实现有顺序表和链式表两种&#xff0c;也就是数组和链表实现。 其中抽象栈类的私有成员函数有operator的重载函数和stack的构造函数&#xff0c;为了保护栈的构造和拷贝被保护。公有成员函数有Stack()&#xff0c;~Stack()&#xff0c;clear()&#xff0c;push()&#xff…

C++成员函数内联(inline)

内联函数是C为提高程序运行速度所做的一项改进。常规函数和内联函数之间的主要区别不在于编写方式,而在于C编译器如何将它们组合到程序中。 当程序执行函数调用时,系统要为即将调用的函数创建栈空间(栈帧),保存现在正在执行的函数数据(保护现场),传递参数以及控制程序执…

Python的主要应用领域

Python是一种广泛应用的高级编程语言&#xff0c;以其强大的功能和简洁的语法受到开发者的青睐。自1991年首次发布以来&#xff0c;Python的应用范围已经从简单的脚本语言发展到支持多种编程范式&#xff08;包括面向对象、命令式、函数式编程和过程式&#xff09;的全功能语言…

spring bean的生命周期你了解么

Spring Bean的生命周期是指在Spring容器中创建、初始化、使用和销毁Bean实例的整个过程。理解Spring Bean的生命周期对于开发者来说非常重要&#xff0c;因为它涉及到在不同的生命周期阶段执行自定义逻辑的机会。下面是关于Spring Bean生命周期的详细解释&#xff0c;包括各个阶…

修复提高PDF清晰度软件

修复提高PDF清晰度软件 使用python脚本对pdf进行优化&#xff0c;提高pdf清晰度&#xff0c;使文字更加清晰&#xff0c;观感更佳。仅适用黑白扫描版pdf&#xff0c;且文字较为清晰&#xff0c;若字形笔画较模糊会更加模糊。 注意事项 cpu满核极速运行&#xff0c;软件可能卡…