【golang必备算法】 Letecode 146. LRU 缓存机制
力扣链接:146. LRU 缓存机制

思路:哈希表 + 双向链表

为什么必须要用双向链表?
因为我们需要删除操作。删除一个节点不光要得到该节点本身的指针,也需要操作其前驱节点的指针,而双向链表才能支持直接查找前驱,保证操作的时间复杂度 O(1)。
为什么要在链表中同时存储 key 和 val,而不是只存储 val?
当缓存容量已满,我们不仅仅要删除最后一个节点,还要把哈希表 中映射到该节点的 key 同时删除,而这个 key 只能由 节点得到。如果 节点结构中只存储 val,那么我们就无法得知 key 是什么,就无法删除 哈希表中的键,造成错误。
代码
我这里是向尾部添加数据,所以头部的是不活跃的数据值
type LRUCache struct { //LRU 缓存结构
capacity int // 容量
m map[int]*Node //哈希表
cache *NodeList //双向链表
}
type Node struct{ //节点结构
key int
value int
prev *Node //前一个节点
next *Node //后一个节点
}
func initNode(key,value int)*Node{ //初始化节点
return &Node{
key:key,
value:value,
}
}
type NodeList struct{ //链表结构
head *Node //链表头节点
last *Node //链表尾节点
size int //元素个数
}
func initList ()*NodeList{ //初始化链表
dil:=&NodeList{
head:initNode(0,0),
last:initNode(0,0),
size:0,
}
dil.head.next=dil.last
dil.last.prev=dil.head
return dil
}
func (this *NodeList)addNodeinlist(node *Node){ //向链表中插入节点,向链表尾部插节点
node.prev=this.last.prev
this.last.prev=node
node.prev.next=node
node.next=this.last
this.size++
}
func (this *NodeList)deleteNodeinlist (node *Node){ //删除链表中的某一结点
node.prev.next=node.next
node.next.prev=node.prev
node.next=nil
node.prev=nil
this.size--
}
func (this *NodeList)delfirstNode()*Node{ //删除第一个节点,并且返回
if this.head.next==this.last{
return nil
}
t:=this.head.next
this.deleteNodeinlist(t)
return t
}
func Constructor(capacity int) LRUCache { //初始化 LRU 缓存
return LRUCache{
capacity:capacity,
m:make(map[int]*Node,0),
cache:initList(),
}
}
func (this *LRUCache)addkey(key,value int){ //添加元素
node:=initNode(key,value)
//增加map映射
this.m[key]=node
//在链表中添加元素
this.cache.addNodeinlist(node)
}
func (this *LRUCache)makekey(key int){ // 将某个 key 调整为最近使用的元素
//找到节点
node:=this.m[key]
//删除节点
this.cache.deleteNodeinlist(node)
// 添加到链表尾部
this.cache.addNodeinlist(node)
}
func (this *LRUCache)deletekey(key int){ //删除元素
//删除链表中节点
this.cache.deleteNodeinlist(this.m[key])
//删除map映射
delete(this.m,key)
}
func (this *LRUCache)deletefirkey(){ //删除最久未使用的元素
// 链表的第一个就是最近最少使用的元素
node:=this.cache.delfirstNode()
// 删除映射
delete(this.m,node.key)
}
func (this *LRUCache) Get(key int) int {
if _,ok:=this.m[key];ok{
//存在
this.makekey(key) //将某个 key 调整为最近使用的元素
return this.m[key].value
}else{
//不存在
return -1
}
}
func (this *LRUCache) Put(key int, value int) {
// 检查key存不存在
if _,ok:=this.m[key];ok{
//存在
//删除元素
this.deletekey(key)
//添加元素到尾部
this.addkey(key,value)
}else{
//不存在
if this.capacity==this.cache.size{
//缓存达到上限
//删除最久未使用的元素
this.deletefirkey()
}
//添加元素到尾部
this.addkey(key,value)
}
}
参考:
https://leetcode-cn.com/problems/lru-cache/solution/jian-dan-shi-li-xiang-xi-jiang-jie-lru-s-exsd/
【golang必备算法】 Letecode 146. LRU 缓存机制的更多相关文章
- Java实现 LeetCode 146 LRU缓存机制
146. LRU缓存机制 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - ...
- 力扣 - 146. LRU缓存机制
目录 题目 思路 代码 复杂度分析 题目 146. LRU缓存机制 思路 利用双链表和HashMap来解题 看到链表题目,我们可以使用头尾结点可以更好进行链表操作和边界判断等 还需要使用size变量来 ...
- 146. LRU 缓存机制 + 哈希表 + 自定义双向链表
146. LRU 缓存机制 LeetCode-146 题目描述 题解分析 java代码 package com.walegarrett.interview; /** * @Author WaleGar ...
- [Leetcode]146.LRU缓存机制
Leetcode难题,题目为: 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key ...
- 【力扣】146. LRU缓存机制
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果关键字 (key) ...
- 146. LRU缓存机制
题目描述 运用你所掌握的数据结构,设计和实现一个LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 (key ...
- Leetcode 146. LRU 缓存机制
前言 缓存是一种提高数据读取性能的技术,在计算机中cpu和主内存之间读取数据存在差异,CPU和主内存之间有CPU缓存,而且在内存和硬盘有内存缓存.当主存容量远大于CPU缓存,或磁盘容量远大于主存时,哪 ...
- leetcode:146. LRU缓存机制
题目描述: 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 ( ...
- LeetCode 146. LRU缓存机制(LRU Cache)
题目描述 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 (k ...
随机推荐
- 洛谷4035 JSOI2008球形空间产生器 (列柿子+高斯消元)
题目链接 qwq 首先看到这个题,感觉就应该从列方程入手. 我们设给定的点的坐标矩阵是\(x\),然后球心坐标\(a_1,a_2....a_n\) 根据欧几里得距离公式,对于一个\(n维空间\)的第\ ...
- SpringBoot-自动装配2
配置文件到底能写什么?怎么写? SpringBoot官方文档中有大量的配置,直接去记忆的话,好像不是我们程序员的行事风格! 分析自动配置原理 能自动配置的组件一般都有命名为下面规则的两个类: xxxx ...
- 2021-2022 20211420 《信息安全专业导论》安装Linux操作系统并学习Linux基础
作业信息 |作业属于|https://edu.cnblogs.com/campus/besti/2021-2022-1fois |作业要求|https://edu.cnblogs.com/campus ...
- 【UE4 C++ 基础知识】<15> 智能指针 TSharedPtr、UniquePtr、TWeakPtr、TSharedRef
基本概念 UE4 对 UObject 对象提供垃圾回收 UE4 对原生对象不提供垃圾回收,需要手动进行清理 方式 malloc / free new / delete new与malloc的区别在于, ...
- Servlet学习一(Servlet的使用流程)
一.servlet运行流程 运行流程:浏览器发送请求到服务器,服务器根据url地址在webapps中寻找对应的项目文件夹然后再web.xml中检索对应的servlet,并进行调用二.servlet类写 ...
- 如何获取ISO8601定义的Work Week
工作中遇到一个需求,需要在打印标签的时候打印生产当天的工作周.工作周按照ISO-8601定义的标准计算.找到两种方案. Excel函数 C#代码 Excel函数 非常简单,调用一个Excel自带函数就 ...
- 普通用户在命令终端使用Python脚本连入校园网
普通用户在命令终端使用Python脚本连入校园网 想要连入校园网的步骤: 浏览器输入对应的IP地址,输入账号密码连网: 下载对应软件,输入账号密码连网: 而面对没有界面的服务器,而你又没有root权限 ...
- Scrum Meeting 0602
零.说明 日期:2021-6-2 任务:简要汇报两日内已完成任务,计划后两日完成任务 一.进度情况 组员 负责 两日内已完成的任务 后两日计划完成的任务 困难 qsy PM&前端 完成后端管理 ...
- [no code][scrum meeting] Beta 5
$( "#cnblogs_post_body" ).catalog() 例会时间:5月18日14:30,主持者:叶开辉 下次例会时间:5月19日11:30,主持者:黎正宇 一.工作 ...
- 晶振在电路设计时关于负载电容CL大小取值特别需要注意什么?
在无源晶体的设计中,经常遇到负载电容CL的大小取值.晶振设计与精度的提高.KHz无源晶振的停止.音叉晶体谐振器的精度漂移以及精度和无源晶振在高温下的精度是否等于低温的精度烦忧的问题等. 无源晶体振荡器 ...