【LeetCode】LRU快取
阿新 • • 發佈:2022-04-06
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) } }