LeetCode 热题 100_LRU 缓存(35_146_中等_C++)(哈希表 + 双向链表)(构造函数声明+初始化列表=进行变量初始化和赋值)

LeetCode 热题 100_LRU 缓存(35_146)

    • 题目描述:
    • 输入输出样例:
    • 题解:
      • 解题思路:
      • 代码实现(思路一(哈希表 + 双向链表)):
      • 部分代码解读

题目描述:

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。

输入输出样例:

示例 :
输入
[“LRUCache”, “put”, “put”, “get”, “put”, “get”, “put”, “get”, “get”, “get”]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1); // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4

提示:
1 <= capacity <= 3000
0 <= key <= 10000
0 <= value <= 105
最多调用 2 * 105 次 get 和 put

题解:

解题思路:

思路一(哈希表 + 双向链表):
1、通过题目分析,put操作:如果key不在缓存中那我们需要进行结点的插入操作,若插入时缓存已满则先删除最久未访问的结点再插入。这里我们可以想到双向链表,头部存储最近访问结点,尾部存储最久未访问结点。get操作,若存在key则返回结点的value,这里get相当于一个查找,所以我们可以想到哈希表,这样我们就能快速的进行结点的查找和定位。

2、具体思路如下:
① 我们创建一个头结点和一个额外的尾结点来方便结点的插入和删除操作。
② 插入操作(put):我们将刚插入的元素或者最近使用的元素放在链表的头部,则尾部为最长时间未使用的元素。
     若要插入结点key时,之前存在序号为key的结点则移到链表头部。
     若要插入节点key时,之前不存在序号为key的结点,且结点数未满则插入链表头部,若结点数已满则插入后删除尾结点。

③ 获取操作(get):分析到获取我们很快能想到哈希表,因哈希表能让我们快速的进行查找操作,所以上述插入和删除时需要维护一个哈希表。
     若结点不在哈希表中则返回-1。
     若存在哈希表中则返回值,并将结点移动到头部。

力扣官方题解链接(有缓存 get() 和put () 过程图很不错)

3、复杂度分析
① 时间复杂度:对于 put 和 get 都是 O(1)。
② 空间复杂度:O(capacity),因为哈希表和双向链表最多存储 capacity+1 个元素。

代码实现(思路一(哈希表 + 双向链表)):

struct DLinkedNode{
	int key,value;
	DLinkedNode* prev;
	DLinkedNode* next;
	DLinkedNode():key(0),value(0),prev(nullptr),next(nullptr){}
	DLinkedNode(int _key,int _value):key(_key),value(_value),prev(nullptr),next(nullptr){} 
}; 

class LRUCache {

private:
	//存储缓存中的节点数 
	unordered_map<int,DLinkedNode*> cache;
	//head和tail方便结点的操作 
	DLinkedNode* head;
	DLinkedNode* tail;
	//size是当前缓存中的结点数,capacity是缓存最大的容量 
	int size;
	int capacity;
	
public:
	//初始化缓存,缓存容量为 _capacity,一开始缓存存入size=0个结点 
    LRUCache(int _capacity):capacity(_capacity),size(0){
    	head=new DLinkedNode();
    	tail=new DLinkedNode();
    	head->next=tail;
    	tail->prev=head;
	}
	//如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 
	int get(int key){
		if(!cache.count(key)){
			return -1;
		}
		//若存在key,则将key对应的结点移动到链表首部,先拆出来,再添加到首部 
		removeNode(cache[key]);
		addToHead(cache[key]);
		return cache[key]->value;
	} 
	
	void put(int key,int value){
		//如果关键字 key 已经存在,则变更其数据值 value
		if(cache.count(key)){
			removeNode(cache[key]);
			addToHead(cache[key]);
			cache[key]->value=value;
		//如果不存在,则向缓存中插入该组 key-value
		}else{
			DLinkedNode *newNode=new DLinkedNode(key,value);
			cache[key]=newNode;
			addToHead(newNode);
			++size;
			//如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
			if(size>capacity){
				DLinkedNode *removed=removeTail();
				cache.erase(removed->key);
				delete removed;
				--size;
			}
		}
	}
	
	//插入链表头部
	void addToHead(DLinkedNode *node){
		node->next=head->next;
		node->prev=head;
		head->next->prev=node;
		head->next=node;
	}
	
	//断开链表尾部(需返回,用于删除哈希表中对应数据)
	DLinkedNode *removeTail(){
		DLinkedNode *node=tail->prev;
		
		tail->prev=node->prev;
		node->prev->next=tail;
		return node; 
	}
	
	//断开结点 
	void removeNode(DLinkedNode* node) {
        node->prev->next = node->next;
        node->next->prev = node->prev;
    }
};

部分代码解读

构造函数声明+初始化列表进行变量初始化和赋值

//下方代码的用法和第一行相同,是构造函数初始化列表,对变量初始化和赋值
DLinkedNode(int _key,int _value):key(_key),value(_value),prev(nullptr),next(nullptr){} 
//构造函数
//初始化 capacity 成员变量 为传递给构造函数的参数 _capacity
//初始化 size 成员变量 为 0,表示缓存初始化时为空。
LRUCache(int _capacity):capacity(_capacity),size(0){}

LeetCode 热题 100_LRU 缓存(35_146)原题链接
欢迎大家和我沟通交流(✿◠‿◠)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

7. petalinux 根文件系统配置(package group)

根文件系统配置&#xff08;Petalinux package group&#xff09; 当使能某个软件包组的时候&#xff0c;依赖的包也会相应被使能&#xff0c;解决依赖问题&#xff0c;在配置页面的help选项可以查看需要安装的包 每个软件包组的功能: packagegroup-petalinux-audio包含与音…

基于Spring Boot的个人健康管理系统

一、系统背景与意义 随着现代生活节奏的加快和人们健康意识的日益增强&#xff0c;个人健康管理成为了人们关注的焦点。然而&#xff0c;传统的健康管理方式往往依赖于纸质记录、定期体检等手段&#xff0c;不仅效率低下&#xff0c;而且难以实现对健康数据的持续跟踪和深入分…

上手教程:使用Terraform打造弹性VPC架构

最近Akamai发布的虚拟专用云&#xff08;VPC&#xff09;功能提供了一种隔离的网络&#xff0c;让云资源可以用私密的方式进行通信。 关于Akamai VPC功能&#xff0c;最棒的地方在于它有着极高的灵活性。用户可以通过Cloud Manager、开发人员工具&#xff08;如CLI&#xff09…

要查询 `user` 表中 `we_chat_subscribe` 和 `we_chat_union_id` 列不为空的用户数量

文章目录 1、we_chat_subscribe2、we_chat_union_id 1、we_chat_subscribe 要查询 user 表中 we_chat_subscribe 列不为空的用户数量&#xff0c;你可以使用以下 SQL 查询语句&#xff1a; SELECT COUNT(*) FROM user WHERE we_chat_subscribe IS NOT NULL;解释&#xff1a; …

【论文复现】进行不同视角图像的拼接

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀ 进行不同视角图像的拼接 背景描述算法简介SIFT算法原理代码原理代码部署核心代码拼接结果其他的图片如何进行拼接&#xff1f; 修改内容&…

xxl-job 简单的入门到实战

本文是参考官方文档自己实践一次&#xff0c;纯享版&#xff0c;大致也是作者边写博客边去跟着官方文档实现 一、前期准备 1、官网地址 GitHub地址&#xff1a; GitHub - xuxueli/xxl-job: A distributed task scheduling framework.&#xff08;分布式任务调度平台XXL-JOB&…

数字后端培训项目Floorplan常见问题系列专题续集1

今天继续给大家分享下数字IC后端设计实现floorplan阶段常见问题系列专题。这些问题都是来自于咱们社区IC后端训练营学员提问的问题库。目前这部分问题库已经积累了4年了&#xff0c;后面会陆续分享这方面的问题。 希望对大家的数字后端学习和工作有所帮助。 数字后端项目Floor…

江苏捷科云:可视化平台助力制造企业智能化管理

公司简介 江苏捷科云信息科技有限公司&#xff08;以下简称“捷科”&#xff09;是一家专注于云平台、云储存、云管理等产品领域的创新型企业&#xff0c;集研发、生产和销售于一体&#xff0c;致力于在网络技术领域打造尖端品牌。在推动制造业企业数字化转型的进程中&#xf…

【视觉惯性SLAM:对极几何】

对极几何&#xff08;Epipolar Geometry&#xff09;介绍 对极几何是立体视觉中的核心内容之一&#xff0c;它描述了两个相机在观察同一个三维场景时&#xff0c;成像平面之间的几何关系。对极几何能够约束图像中对应点的位置关系&#xff0c;是双目立体匹配、三维重建、以及位…

从Condition开始,回顾AQS

Synchronized和Reentrantlock的挂起逻辑 synchronized中有两个核心的结构 EntryList cxq&#xff1a;等待拿锁的线程存储位置Waitset&#xff1a;被执行wait方法的线程存储位置 流转&#xff1a; 线程获取锁资源失败&#xff0c;扔到EntryList cxq线程持有锁资源&#x…

umi : 无法加载文件 D:\software\nodejs\node_global\umi.ps1,因为在此系统上禁止运行脚本。

问题详情 2、解决方法 1.使用命令 get-ExecutionPolicy查看 显示Restricted&#xff1a;限制 所以要给权限 2. 使用命令&#xff1a;Set-ExecutionPolicy -Scope CurrentUser 3. 会提示为参数提供值 4. 输入&#xff1a; RemoteSigned 具体如下图所示&#xff0c;成功解决。 报…

Redis篇--常见问题篇4--大Key(Big Key,什么是大Key,影响及使用建议)

1、概述 大Key&#xff1a;通常是指值&#xff08;Value&#xff09;的长度非常大&#xff0c;实际上键&#xff08;Key&#xff09;长度很大也算。通常来说&#xff0c;键本身不会很长&#xff0c;占用的内存较少&#xff0c;因此判断一个键是否为bigKey主要看它对应的值的大…

02、并发编程的三大特性

并发编程有三大特性分别是&#xff0c;原子性&#xff0c;可见性&#xff0c;有序性。会产生这些特性的根本原因是现在的服务器都是多CPU多核心数的&#xff0c;每个CPU都有自己单独的一套缓存和pc系统&#xff0c;而且程序在运行时按照JMM的规范&#xff0c;它们是需要先把数据…

基于Java+Jsp Servlet Mysql实现的Java Web在线商城项目系统设计与实现

一、前言介绍&#xff1a; 1.1 项目摘要 随着互联网技术的飞速发展&#xff0c;电子商务已成为现代商业活动的重要组成部分。在线商城作为电子商务的一种重要形式&#xff0c;以其便捷性、高效性和广泛覆盖性&#xff0c;受到了越来越多消费者的青睐。同时&#xff0c;随着消…

【安全测试相关知识】

安全测试介绍 背景 在当前信息技术快速发展的背景下&#xff0c;网络安全问题日益严峻&#xff0c;数据泄露、黑客攻击、病毒传播等安全事件层出不穷&#xff0c;给个人、企业乃至国家带来严重威胁。所以安全测试已成为企业和国家关注的重心 作用 安全测试是确保软件系统安…

WPS如何快速将数字金额批量转换成中文大写金额,其实非常简单

大家好&#xff0c;我是小鱼。 在日常的工作中经常会遇到需要使用金额大写的情况&#xff0c;比如说签订业务合同时一般都会标注大写金额&#xff0c;这样是为了安全和防止串改。但是很多人也许不太熟悉金额大写的方法和习惯&#xff0c;其它没有关系&#xff0c;我们在用WPS制…

Element-ui的使用教程 基于HBuilder X

文章目录 1.Element-ui简介2.使用HBuilderX 创建一个基于Vue3的项目 &#xff08;由于是使用的基于Vue3的Element-ui&#xff09;3.安装element-ui4.在项目里完全引用element-ui5.引用组件6.运行项目 1.Element-ui简介 Element&#xff0c;一套为开发者、设计师和产品经理准备…

MySQL的架构设计和设计模式

1. 数据库设计模式与范式 数据库设计模式是解决数据库设计中常见问题的一种思维方式&#xff0c;它提供了一套解决方案。以下是一些常见的数据库设计模式和范式&#xff1a; 实体-关系模型&#xff08;Entity-Relationship Model&#xff09;&#xff1a;通过实体和实体之间的…

【MySQL】十三,关于MySQL的全文索引

MySQL的全文索引用于搜索文本中的关键字&#xff0c;类似于like查询。 演示 建表 CREATE TABLE demo (id INT(11) NOT NULL,name CHAR(30) NOT NULL,age INT(11) NOT NULL,info VARCHAR(255),primary key(id),fulltext index futxt_idx_info(info) );此表的默认存储引擎为In…

Aloudata 入选 IDC「GenAI+Data」中国市场代表厂商

近期&#xff0c;国际知名技术研究与咨询机构 IDC 发布了《GenAIData 市场趋势分析及最佳实践案例》报告&#xff0c;总结了当前主要市场特点和数据变化影响&#xff0c;并给出技术布局建议&#xff0c;以供市场参考。报告中还绘制了 GenAIData 发展趋势图&#xff0c;从市场需…