题目
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:
LRUCache(int capacity)
以正整数作为容量capacity
初始化 LRU 缓存int get(int key)
如果关键字key
存在于缓存中,则返回关键字的值,否则返回-1
。void put(int key, int value)
如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
进阶:你是否可以在 O ( 1 ) O(1) O(1) 时间复杂度内完成这两种操作?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lru-cache
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解分析
- 缓存容量限制
- 达到容量删除最久未使用的key和value,
方法一:维护两个字典表,一个是key-value,另一个是key-time。其中:get()和put()的复杂度为 O ( c a p a c i t y ) O(capacity) O(capacity)。
class LRUCache:
def __init__(self, capacity):
self.capacity = capacity
# cache dict
self.cache = {}
# time dict
self.times = {}
def get(self, key):
# not exist return -1
if key not in self.cache.keys():
return -1
# add one time for all keys
for k, t in self.times.items():
self.times[k] = t + 1
# set the key operated zero time
self.times[key] = 0
return self.cache[key]
def put(self, key, value):
# if key in the cache, change the value of key
if key in self.cache.keys():
for k, t in self.times.items():
self.times[k] = t + 1
self.cache[key] = value
self.times[key] = 0
else:
# if capacity not full
if self.capacity > len(self.cache):
for k, t in self.times.items():
self.times[k] = t + 1
self.cache[key] = value
self.times[key] = 0
else: # if capacity full, delete the key of max times
k,t = None, None
for m, n in self.times.items():
if k is None:
k = m
t = n
else:
if n > t:
k = m
t = n
self.cache.pop(k)
self.times.pop(k)
for k, t in self.times.items():
self.times[k] = t + 1
self.cache[key] = value
self.times[key] = 0
方法二:维护一个cache字典和一个双向链表,其中get()和put()的时间复杂度为 O ( 1 ) O(1) O(1)
# define double link
class DLinkedNode:
def __init__(self, key=None, value=None, prev=None, next=None):
self.key = key
self.value = value
self.prev = prev
self.next = next
class LRUCache:
def __init__(self, capacity):
self.capacity = capacity
self.cache = {}
self.head = DLinkedNode()
self.tail = DLinkedNode()
self.head.next = self.tail
self.tail.prev = self.head
def get(self, key):
if key not in self.cache.keys():
return -1
self.remove(self.cache[key])
self.addNode(self.cache[key])
return self.cache[key].value
def put(self, key, value):
if key in self.cache.keys():
node = self.cache[key]
node.value = value
self.remove(node)
self.addNode(node)
else:
if self.capacity > len(self.cache):
node = DLinkedNode(key=key, value=value)
self.addNode(node)
self.cache[key] = node
else:
self.cache.pop(self.removeTail().key)
node = DLinkedNode(key=key, value=value)
self.addNode(node)
self.cache[key] = node
def addNode(self, node):
node.prev = self.head
node.next = self.head.next
self.head.next.prev = node
self.head.next = node
def remove(self, node):
node.prev.next = node.next
node.next.prev = node.prev
def removeTail(self):
node = self.tail.prev
self.remove(node)
return node