146. LRU 缓存¶
题目¶
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache
类:
LRUCache(int capacity)
以 正整数 作为容量capacity
初始化 LRU 缓存int get(int key)
如果关键字 key 存在于缓存中,则返回关键字的值,否则返回-1
。void put(int key, int value)
如果关键字key
已经存在,则变更其数据值value
;如果不存在,则向缓存中插入该组key-value
。如果插入操作导致关键字数量超过capacity
,则应该 逐出 最久未使用的关键字。
函数 get
和 put
必须以 O(1)
的平均时间复杂度运行。
示例 1:
输入:
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出:
[null, null, null, 1, null, -1, null, -1, 3, 4]
题解¶
双向链表
type LRUCache struct {
capacity int
list *list.List
keyToNode map[int]*list.Element
}
type entry struct {
key int
val int
}
func Constructor(capacity int) LRUCache {
return LRUCache{
capacity: capacity,
list: list.New(),
keyToNode: map[int]*list.Element{},
}
}
func (this *LRUCache) Get(key int) int {
node := this.keyToNode[key]
if node == nil {
return -1
}
this.list.MoveToFront(node)
return node.Value.(entry).val
}
func (this *LRUCache) Put(key int, value int) {
if node := this.keyToNode[key]; node != nil {
// 更新
node.Value = entry{key, value}
this.list.MoveToFront(node)
return
}
this.keyToNode[key] = this.list.PushFront(entry{key, value})
if len(this.keyToNode) > this.capacity {
delete(this.keyToNode, this.list.Remove(this.list.Back()).(entry).key)
}
}
type node struct {
key, val int
prev, next *node
}
type LRUCache struct {
capacity int
cache map[int]*node
head, tail *node
}
func Constructor(capacity int) LRUCache {
head := new(node)
tail := new(node)
head.next = tail
tail.prev = head
return LRUCache{
capacity: capacity,
cache: make(map[int]*node, capacity),
head: head,
tail: tail,
}
}
func (this *LRUCache) Get(key int) int {
n, ok := this.cache[key]
if !ok {
return -1
}
this.moveToFront(n)
return n.val
}
func (this *LRUCache) Put(key int, value int) {
n, ok := this.cache[key]
if ok {
n.val = value
this.moveToFront(n)
return
}
if len(this.cache) == this.capacity {
back := this.tail.prev
this.remove(back)
delete(this.cache, back.key)
}
n = &node{key: key, val: value}
this.pushFront(n)
this.cache[key] = n
}
func (this *LRUCache) moveToFront(n *node) {
this.remove(n)
this.pushFront(n)
}
func (this *LRUCache) remove(n *node) {
n.prev.next = n.next
n.next.prev = n.prev
n.prev = nil
n.next = nil
}
func (this *LRUCache) pushFront(n *node) {
n.prev = this.head
n.next = this.head.next
this.head.next.prev = n
this.head.next = n
}
class Node:
# 提高访问属性的速度,并节省内存
__slots__ = 'prev', 'next', 'key', 'value'
def __init__(self, key=0, value=0):
self.key = key
self.value = value
class LRUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.dummy = Node() # 哨兵节点
self.dummy.prev = self.dummy
self.dummy.next = self.dummy
self.key_to_node = dict()
def get_node(self, key: int) -> Optional[Node]:
if key not in self.key_to_node: # 没有这本书
return None
node = self.key_to_node[key] # 有这本书
self.remove(node) # 把这本书抽出来
self.push_front(node) # 放在最上面
return node
def get(self, key: int) -> int:
node = self.get_node(key)
return node.value if node else -1
def put(self, key: int, value: int) -> None:
node = self.get_node(key)
if node: # 有这本书
node.value = value # 更新 value
return
self.key_to_node[key] = node = Node(key, value) # 新书
self.push_front(node) # 放在最上面
if len(self.key_to_node) > self.capacity: # 书太多了
back_node = self.dummy.prev
del self.key_to_node[back_node.key]
self.remove(back_node) # 去掉最后一本书
# 删除一个节点(抽出一本书)
def remove(self, x: Node) -> None:
x.prev.next = x.next
x.next.prev = x.prev
# 在链表头添加一个节点(把一本书放在最上面)
def push_front(self, x: Node) -> None:
x.prev = self.dummy
x.next = self.dummy.next
x.prev.next = x
x.next.prev = x
class Node:
def __init__(self, key=0, val=0):
self.key = key
self.val = val
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.cache = {}
self.head = Node()
self.tail = Node()
self.capacity = capacity
self.size = 0
self.head.next = self.tail
self.tail.prev = self.head
def get(self, key: int) -> int:
if key not in self.cache:
return -1
node = self.cache[key]
self.move_to_head(node)
return node.val
def put(self, key: int, value: int) -> None:
if key in self.cache:
node = self.cache[key]
node.val = value
self.move_to_head(node)
else:
node = Node(key, value)
self.cache[key] = node
self.add_to_head(node)
self.size += 1
if self.size > self.capacity:
node = self.remove_tail()
self.cache.pop(node.key)
self.size -= 1
def move_to_head(self, node):
self.remove_node(node)
self.add_to_head(node)
def remove_node(self, node):
node.prev.next = node.next
node.next.prev = node.prev
def add_to_head(self, node):
node.next = self.head.next
node.prev = self.head
self.head.next = node
node.next.prev = node
def remove_tail(self):
node = self.tail.prev
self.remove_node(node)
return node
复杂度¶
- 时间复杂度:
- 空间复杂度:
,其中 为 的调用次数。