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)
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。