Appearance
Approach: Hash map + doubly linked list; move accessed nodes to the head, evict from the tail when over capacity.
Complexity: O(1) per op, O(capacity) space
go
type Node struct {
key int
val int
prev *Node
next *Node
}
type LRUCache struct {
capacity int
cache map[int]*Node
head *Node
tail *Node
}
func Constructor(capacity int) LRUCache {
lru := LRUCache{
capacity: capacity,
cache: make(map[int]*Node, capacity),
head: &Node{},
tail: &Node{},
}
lru.head.next = lru.tail
lru.tail.prev = lru.head
return lru
}
func (this *LRUCache) Get(key int) int {
if node, ok := this.cache[key]; ok {
this.moveToHead(node)
return node.val
}
return -1
}
func (this *LRUCache) Put(key int, value int) {
if node, ok := this.cache[key]; ok {
node.val = value
this.moveToHead(node)
return
}
if len(this.cache) == this.capacity {
tail := this.tail.prev
this.removeNode(tail)
delete(this.cache, tail.key)
}
node := &Node{key: key, val: value}
this.cache[key] = node
this.addToHead(node)
}
func (this *LRUCache) moveToHead(node *Node) {
this.removeNode(node)
this.addToHead(node)
}
func (this *LRUCache) addToHead(node *Node) {
node.prev = this.head
node.next = this.head.next
this.head.next.prev = node
this.head.next = node
}
func (this *LRUCache) removeNode(node *Node) {
node.prev.next = node.next
node.next.prev = node.prev
}
/**
* Your LRUCache object will be instantiated and called as such:
* obj := Constructor(capacity);
* param_1 := obj.Get(key);
* obj.Put(key,value);
*/