146. LRU缓存机制

运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。

获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。

进阶:

你是否可以在 O(1) 时间复杂度内完成这两种操作?

示例:

LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // 返回  1
cache.put(3, 3);    // 该操作会使得密钥 2 作废
cache.get(2);       // 返回 -1 (未找到)
cache.put(4, 4);    // 该操作会使得密钥 1 作废
cache.get(1);       // 返回 -1 (未找到)
cache.get(3);       // 返回  3
cache.get(4);       // 返回  4

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lru-cache
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解法: 

#include <iostream>
#include <unordered_map>
#include <memory>
#include <list>
#include <utility>
using namespace std;class LRUCache
{
public:LRUCache(int capacity) //缓存容量{cap = capacity;}/*存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。获取数据 get(key) - 如果密钥 (key) */int get(int key)  {auto it = m.find(key);if (it == m.end()) return -1;l.splice(l.begin(), l, it->second);return it->second->second;}/*写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间*/void put(int key, int value){auto it = m.find(key);if (it != m.end())l.erase(it->second);l.push_front(make_pair(key, value));m[key] = l.begin();if (m.size() > cap){int k = l.rbegin()->first;l.pop_back();m.erase(k);}}private:int cap;list<pair<int/*关键字*/, int>> l;unordered_map<int/*关键字*/, list<pair<int, int>>::iterator> m;
};int main()
{LRUCache cache(2 /* 缓存容量 */);cache.put(1, 1);cache.put(2, 2);cout << cache.get(1) << endl;       // 返回  1cache.put(3, 3);    // 该操作会使得密钥 2 作废cout << cache.get(2) << endl;       // 返回 -1 (未找到)cache.put(4, 4);     // 该操作会使得密钥 1 作废cout << cache.get(1) << endl;       // 返回 -1 (未找到)cout << cache.get(3) << endl;       // 返回  3cout << cache.get(4) << endl;       // 返回  4return 0;
}

 

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

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

相关文章

dup和dup2函数

#include <unistd.h> int dup(int oldfd); int dup2(int oldfd, int newfd); 作用&#xff1a;dup函数实现对一个文件的文件描述符进行复制&#xff0c;复制之后该进程就会新增加一一个文件描述符指向该文件&#xff08;即实现同一个文件对应多个文件描述符&#xff0…

fcntl函数(网络编程会用)

#include <unistd.h> #include <fcntl.h> int fcntl&#xff08;int fd, int cmd&#xff09;&#xff1b; int fcntl&#xff08;int fd, int cmd, long arg&#xff09;&#xff1b;//long 长整型 int fcntl&#xff08;int fd, int cmd, struct flock *lock…

189. 旋转数组

给定一个数组&#xff0c;将数组中的元素向右移动 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: [1,2,3,4,5,6,7] 和 k 3 输出: [5,6,7,1,2,3,4] 解释: 向右旋转 1 步: [7,1,2,3,4,5,6] 向右旋转 2 步: [6,7,1,2,3,4,5] 向右旋转 3 步: [5,6,7,1,2,3,4]示例 2: 输…

58. 最后一个单词的长度

给定一个仅包含大小写字母和空格 的字符串&#xff0c;返回其最后一个单词的长度。 如果不存在最后一个单词&#xff0c;请返回 0 。 说明&#xff1a;一个单词是指由字母组成&#xff0c;但不包含任何空格的字符串。 示例: 输入: "Hello World" 输出: 5 clas…

CPU和MMU(内存管理单元)

CPU的架构&#xff1a;要求能够理解从源程序到微指令的整个经历过程&#xff1a;存储器的层次结构&#xff08;网络资源下载到硬盘、磁盘缓存、内存、Cache、寄存器&#xff09;&#xff1b;CPU的四大部分&#xff1a;ALU、CU、中断系统和寄存器&#xff1b;程序执行的整个过程…

【C++ Primer | 09】容器适配器

一、stack s.push(): 向栈内压入一个成员&#xff1b; s.pop(): 从栈顶弹出一个成员&#xff1b; s.empty(): 如果栈为空返回true&#xff0c;否则返回false&#xff1b; s.top(): 返回栈顶&#xff0c;但不删除成员&#xff1b; s.size(): 返回栈内元素…

进程控制块PCB(进程描述符)

&#xff08;1&#xff09;PCB 每个进程在内核中都有一个进程控制块&#xff08;PCB&#xff09;来维护进程相关的信息&#xff0c;Linux内核的进程控制块是task_struct结构体。grep -r “task_struct” / 可以查找根目录下&#xff0c;包含task_struct的文件文件。或者 find…

103. 二叉树的锯齿形层次遍历

给定一个二叉树&#xff0c;返回其节点值的锯齿形层次遍历。&#xff08;即先从左往右&#xff0c;再从右往左进行下一层遍历&#xff0c;以此类推&#xff0c;层与层之间交替进行&#xff09;。 例如&#xff1a; 给定二叉树 [3,9,20,null,null,15,7], 3 / \ 9 20 /…

fork、getpid、getppid函数

#include <unistd.h> pid_t fork(void); 作用&#xff1a;创建一个子进程。 到目前为止&#xff0c;我们可以直到两种创建进程的方法&#xff1a;1. 通过执行二进制文件来创建一个进程&#xff0c;如&#xff1a;./a.out /bin/ls&#xff1b;2.通过fork函数来创建一个…

107. 二叉树的层次遍历 II

给定一个二叉树&#xff0c;返回其节点值自底向上的层次遍历。 &#xff08;即按从叶子节点所在层到根节点所在的层&#xff0c;逐层从左向右遍历&#xff09; 例如&#xff1a; 给定二叉树 [3,9,20,null,null,15,7], 3/ \9 20/ \15 7返回其自底向上的层次遍历为&#xff…

循环创建N个子进程

以循环创建5个进程为例&#xff0c;给出如下代码&#xff0c;分析其错误&#xff1a; #include <stdio.h> #include <stdlib.h> #include <unistd.h>int main(void) {int i;pid_t pid;printf("xxxxxxxxxxx\n");for (i 0; i < 5; i){pid fork…

【C++ Primer | 19】控制内存分配

1. 测试代码&#xff1a; #include <iostream> #include <new> #include <cstring> #include <cstdlib> using namespace std;void* operator new(size_t size) {cout << "global Override operator new" << endl;if (void* p…

getuid、geteuid、getgid和getegid函数

#include <unistd.h> #include <sys/types.h> uid_t getuid(void); uid_t geteuid(void); 作用&#xff1a;getuid返回当前进程的实际用户ID&#xff1b;geteuid返回当前用户的有效用户ID。这两个总是成功&#xff0c;不会失败。 #include <unistd.h> #…

【第15章】虚函数

一、为什么基类中的析构函数要声明为虚析构函数&#xff1f; 直接的讲&#xff0c;C中基类采用virtual虚析构函数是为了防止内存泄漏。具体地说&#xff0c;如果派生类中申请了内存空间&#xff0c;并在其析构函数中对这些内存空间进行释放。假设基类中采用的是非虚析构函数&am…

进程共享(读时共享写时复制)

父子进程之间在刚fork后。父子相同处: 全局变量、.data、.bbs、.text、栈、堆、环境变量、用户ID、宿主目录&#xff08;进程用户家目录&#xff09;、进程工作目录、信号处理方式等等&#xff0c;即0~3G的用户空间是完全一样的。父子不同处: 1.进程ID 2.fork返回值 3.父进…

【C++ Primer | 08】IO库

一、istringstream类 描述&#xff1a;从流中提取数据&#xff0c;支持 >> 操作 这里字符串可以包括多个单词&#xff0c;单词之间使用空格分开 #include <iostream> #include <sstream> using namespace std; int main() {istringstream istr(&quo…

gdb调试(如何跟踪指定进程)

使用gdb调试的时候&#xff0c;gdb只能跟踪一个进程。可以在fork函数调用之前&#xff0c;通过指令设置gdb调试工具跟踪父进程或者是跟踪子进程。默认跟踪父进程。 set follow-fork-mode child 命令设置gdb在fork之后跟踪子进程。 set follow-fork-mode parent 设置跟踪父进程…

【Leetcode | 01】Backtracking

回溯算法序号题号117. 电话号码的字母组合222. 括号生成 39. 组合总和 40. 组合总和 II 46. 全排列 47. 全排列 II 60. 第k个排列 77. 组合 78. 子集 90. 子集 II 93. 复原IP地址 131. 分割回文串 216. 组合总和 III 306. 累加数 357. 计算各个位数不同的数字个数 401. 二进…

1033. 旧键盘打字(20)

旧键盘上坏了几个键&#xff0c;于是在敲一段文字的时候&#xff0c;对应的字符就不会出现。现在给出应该输入的一段文字、以及坏掉的那些键&#xff0c;打出的结果文字会是怎样&#xff1f; 输入格式&#xff1a; 输入在2行中分别给出坏掉的那些键、以及应该输入的文字。其中对…

1038. 统计同成绩学生(20)

本题要求读入N名学生的成绩&#xff0c;将获得某一给定分数的学生人数输出。 输入格式&#xff1a; 输入在第1行给出不超过105的正整数N&#xff0c;即学生总人数。随后1行给出N名学生的百分制整数成绩&#xff0c;中间以空格分隔。最后1行给出要查询的分数个数K&#xff08;不…