1. BM100 设计LRU缓存结构
设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设大小为 k ,操作次数是 n ,并有如下两个功能
1. set(key, value):将记录(key, value)插入该结构
2. get(key):返回key对应的value值
提示:
1.某个key的set或get操作一旦发生,认为这个key的记录成了最常使用的,然后都会刷新缓存。
2.当缓存的大小超过k时,移除最不经常使用的记录。
3.输入一个二维数组与k,二维数组每一维有2个或者3个数字,第1个数字为opt,第2,3个数字为key,value
若opt=1,接下来两个整数key, value,表示set(key, value)
若opt=2,接下来一个整数key,表示get(key),若key未出现过或已被移除,则返回-1
对于每个opt=2,输出一个答案
4.为了方便区分缓存里key与value,下面说明的缓存里key用""号包裹
import sys
class Solution:
def __init__(self,k):
self.k = k
self.out=[]
self.dict_lru =dict()
self.list_lru = []
def LRU(self , operators , k ):
self.k =k
for o in operators:
if o[0] ==1:
self.set(o[1],o[2])
else:
self.out.append(self.get(o[1]))
return self.out
def get(self,key):
if key in self.dict_lru:
self.list_lru.remove(key)
self.list_lru.append(key)
return self.dict_lru[key]
return -1
def set(self,key,value):
if key in self.dict_lru:
self.list_lru.remove(key)
self.list_lru.append(key)
else:
self.list_lru.append(key)
self.dict_lru[key]=value
if len(self.list_lru)>self.k:
self.dict_lru.pop(self.list_lru.pop(0))
for line in sys.stdin.readlines():
line = line.strip()
line = line.replace(' ', '')
a = line.split(']],')
k = int(a[1])
res = []
s = Solution(k)
for item in a[0][2:].split('],['):
m = item.split(',')
if m[0] == '1':
s.set(int(m[1]), int(m[2]))
else:
res.append(s.get(int(m[1])))
print(str(res).replace(' ', ''))
# write code here
二、设计LFU缓存结构
一个缓存结构需要实现如下功能。
- set(key, value):将记录(key, value)插入该结构
- get(key):返回key对应的value值
但是缓存结构中最多放K条记录,如果新的第K+1条记录要加入,就需要根据策略删掉一条记录,然后才能把新记录加入。这个策略为:在缓存结构的K条记录中,哪一个key从进入缓存结构的时刻开始,被调用set或者get的次数最少,就删掉这个key的记录;
如果调用次数最少的key有多个,上次调用发生最早的key被删除
这就是LFU缓存替换算法。实现这个结构,K作为参数给出
数据范围:0 < k \le 10^50<k≤105,|val| \le 2 \times 10^9∣val∣≤2×109
要求:get和set的时间复杂度都是 O(logn)O(logn),空间复杂度是 O(n)O(n)
若opt=1,接下来两个整数x, y,表示set(x, y)
若opt=2,接下来一个整数x,表示get(x),若x未出现过或已被移除,则返回-1
对于每个操作2,返回一个答案
class Node:
def __init__(self, cnt=1, key=None, val=None):
self.key = key
self.val = val
self.prev = None
self.next = None
self.cnt = cnt
class DLL:
def __init__(self):
self.head = Node()
self.tail = Node()
self.head.next = self.tail
self.tail.prev = self.head
def addInFront(self, node):
node.prev = self.head
node.next = self.head.next
self.head.next = node
node.next.prev = node
def remove(self, node):
node.prev.next = node.next
node.next.prev = node.prev
class LFUCache(object):
def __init__(self, capacity):
"""
:type capacity: int
"""
self.nKey = 0
self.capacity = capacity
self.dll = DLL()
self.headerNodes = dict()
self.dataNodes = dict()
headerNode = Node(key=1, val=DLL(), cnt=0)
self.headerNodes[1] = headerNode
self.dll.addInFront(headerNode)
def touch(self, node):
self.headerNodes[node.cnt].val.remove(node)
self.headerNodes[node.cnt].cnt -= 1
node.cnt += 1
freq = node.cnt
if freq not in self.headerNodes:
headerNode = Node(key=freq, val=DLL(), cnt=0)
self.dll.addInFront(headerNode)
self.headerNodes[freq] = headerNode
self.headerNodes[freq].val.addInFront(node)
self.headerNodes[freq].cnt += 1
def get(self, key):
"""
:type key: int
:rtype: int
"""
if self.capacity == 0:
return -1
if key in self.dataNodes:
node = self.dataNodes[key]
self.touch(node)
return node.val
else:
return -1
def put(self, key, value):
"""
:type key: int
:type value: int
:rtype: None
"""
if self.capacity == 0:
return
if key in self.dataNodes:
node = self.dataNodes[key]
self.touch(node)
node.val = value
else:
if self.nKey == self.capacity:
headerNode = self.dll.tail.prev
while headerNode.cnt == 0:
headerNode = headerNode.prev
nodeToRemove = headerNode.val.tail.prev
headerNode.val.remove(nodeToRemove)
headerNode.cnt -= 1
del self.dataNodes[nodeToRemove.key]
self.nKey -= 1
node = Node(key=key, val=value)
self.headerNodes[1].val.addInFront(node)
self.headerNodes[1].cnt += 1
self.dataNodes[key] = node
self.nKey += 1
class Solution:
def LFU(self , operators , k ):
# write code here
lfu = LFUCache(k)
res = []
for op in operators:
if op[0] == 1:
lfu.put(op[1], op[2])
else:
res.append(lfu.get(op[1]))
return res