【LeetCode】LRU缓存
作者:互联网
LRU缓存
题目链接:https://leetcode-cn.com/problems/lru-cache/
双向链表+map
map用来确定链表中是否存在此key的节点
双向链表用来实际存储
每次get,都把get的节点放到链表头部
每次put,两种情况
- key存在,更新value,此节点移到头部
- key不存在,构建新节点,加入头部,此时需要判断新加入节点后是否需要淘汰一个节点,如果需要淘汰,按照lru原则,淘汰最近最久没有使用的尾部节点
性能分析:
时间复杂度:get和put都是O(1)
空间复杂度:O(capacity),capacity是容量
type LinkNode struct {
key,value int
pre,next *LinkNode
}
type LRUCache struct {
size int
capacity int
cache map[int]*LinkNode
head,tail *LinkNode
}
func initLinkNode(key,value int) *LinkNode{
return &LinkNode{
key: key,
value: value,
}
}
func Constructor(capacity int)LRUCache{
lruc:=LRUCache{
capacity: capacity,
cache: make(map[int]*LinkNode),
head: initLinkNode(0,0), // 虚拟头节点
tail: initLinkNode(0,0), // 虚拟尾节点
}
// 串联虚拟头尾节点
lruc.head.next=lruc.tail
lruc.head.pre=lruc.head
return lruc
}
// 在头部添加节点
func (this *LRUCache) addToHead(node *LinkNode){
node.next=this.head.next
node.pre=this.head
this.head.next.pre=node
this.head.next=node
}
// 移动节点到头部
func (this *LRUCache) moveToHead(node *LinkNode){
// 先删除节点,然后将节点添加在头部
this.removeNode(node)
this.addToHead(node)
}
// 删除节点
func (this *LRUCache) removeNode(node *LinkNode){
node.pre.next=node.next
node.next.pre=node.pre
}
// 删除尾部节点(非虚拟节点) 返回被删掉的节点
func (this *LRUCache) removeTail() *LinkNode{
node:=this.tail.pre
this.removeNode(node)
return node
}
func (this *LRUCache) Get(key int) int{
if _,ok:=this.cache[key];!ok{
return -1
}
node:=this.cache[key]
// 每次get 都将其提到头部
this.moveToHead(node)
return node.value
}
func (this *LRUCache) Put(key,value int) {
if _,ok:=this.cache[key];!ok{
// key不存在 直接加入到头部 并更新map信息和size信息
node:=initLinkNode(key,value)
this.addToHead(node)
this.cache[key]=node
this.size++
// 满了,需要驱逐一个元素,选择驱逐尾部元素,同步更新map和size信息
if this.size>this.capacity{
remove:=this.removeTail()
delete(this.cache,remove.key)
this.size--
}
}else {
// key存在 更新value值并提到头部
node:=this.cache[key]
node.value=value
this.moveToHead(node)
}
}
标签:node,缓存,int,value,节点,LRU,key,LinkNode,LeetCode 来源: https://www.cnblogs.com/yinbiao/p/16107700.html