首页 > 试题广场 >

设计LFU缓存结构

[编程题]设计LFU缓存结构
  • 热度指数:23499 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
一个缓存结构需要实现如下功能。
  • set(key, value):将记录(key, value)插入该结构
  • get(key):返回key对应的value值
但是缓存结构中最多放K条记录,如果新的第K+1条记录要加入,就需要根据策略删掉一条记录,然后才能把新记录加入。这个策略为:在缓存结构的K条记录中,哪一个key从进入缓存结构的时刻开始,被调用set或者get的次数最少,就删掉这个key的记录;
如果调用次数最少的key有多个,上次调用发生最早的key被删除
这就是LFU缓存替换算法。实现这个结构,K作为参数给出

数据范围:
要求:get和set的时间复杂度都是 ,空间复杂度是


若opt=1,接下来两个整数x, y,表示set(x, y)
若opt=2,接下来一个整数x,表示get(x),若x未出现过或已被移除,则返回-1

对于每个操作2,返回一个答案
示例1

输入

[[1,1,1],[1,2,2],[1,3,2],[1,2,4],[1,3,5],[2,2],[1,4,4],[2,1]],3

输出

[4,-1]

说明

在执行"1 4 4"后,"1 1 1"被删除。因此第二次询问的答案为-1   

备注:

加上最近访问会超时,不加倒数第二个用例过不去,求大佬优化一下循环,或者加一个最近访问的标记。

#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# lfu design
# @param operators int整型二维数组 ops
# @param k int整型 the k
# @return int整型一维数组
#
class Solution:
    def LFU(self , operators: List[List[int]], k: int) -> List[int]:
        # write code here
        buf = []
        res = []
        for i in operators:
            if i[0] == 1:  # opt=1插入数据
                if i[1] in [j[0] for j in buf]:  # 如果插入数据在缓存里
                    for j in buf:
                        if j[0] == i[1]:  # 找到该数据
                            j[1] = i[2]  # 更新value
                            j[2] += 1  # 访问次数+1
                    # # 调整为最近访问
                    # for j in buf:
                    #     if j[0] == i[1]:
                    #         buf.remove(j)
                    #         buf.append(j)

                else:  # 插入数据不在缓存里
                    if len(buf) >= k:  # 已经存满
                        minfw = min([j[2] for j in buf])  # 找到访问次数最少的
                        for j in buf:
                            if j[2] == minfw:  # 更新插入数据
                                j[0] = i[1]  # 更新key
                                j[1] = i[2]  # 更新value
                                j[2] = 1  # 首次访问
                        # # 调整为最近访问
                        # for j in buf:
                        #     if j[0] == i[1]:
                        #         buf.remove(j)
                        #         buf.append(j)
                    else:  # 还没存满
                        buf.append([i[1], i[2], 1])

            else:  # opt=2访问数据
                if i[1] in [j[0] for j in buf]:  # get(x)在缓存里
                    for j in buf:
                        if j[0] == i[1]:  # 找到该数据
                            j[2] += 1  # 访问次数+1
                            res.append(j[1])
                else:
                    res.append(-1)

        return res
编辑于 2024-03-18 20:47:42 回复(0)
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# lfu design
# @param operators int整型二维数组 ops
# @param k int整型 the k
# @return int整型一维数组
#
class Solution:
    def __init__(self):
        """
        初始化桶及其对应的map集合
        :param capacity:
        """
        self.limit = 1
        self.head = Bucket(0)
        self.bmp = {}

    def get(self, key: int) -> int:
        if key in self.bmp.keys():
            tmp = self.bmp[key]
            self.set(key, tmp.val)
            return tmp.val
        else:
            return -1

    def set(self, key: int, value: int) -> None:
        tmp = None
        bucket = None
        if key in self.bmp.keys():
            tmp = self.remove(key)
        else:
            if len(self.bmp) == self.limit:
                self.remove(self.head.next.head.prev.key)
        if tmp:
            bucket = tmp.bucket
            if bucket.times + 1 == bucket.next.times:
                bucket = bucket.next
            else:
                bucket = Bucket(bucket.times+1)
                bucket.prev = self.head.prev
                self.head.prev = bucket
                bucket.prev.next = bucket
                bucket.next = self.head
        else:
            if len(self.bmp) == self.limit:
                self.remove(self.head.next.prev.key)
            if self.head.next.times == 1:
                bucket = self.head.next
            else:
                bucket = Bucket(1)
                bucket.next = self.head.next
                self.head.next = bucket
                bucket.next.prev = bucket
                bucket.prev = self.head
        tmp = BNode(key, value, bucket)
        tmp.next = bucket.head.next
        bucket.head.next = tmp
        tmp.next.prev = tmp
        tmp.prev = bucket.head
        self.bmp[key] = tmp

    def remove(self, key: int):
        if key in self.bmp:
            tmp = self.bmp[key]
            tmp.prev.next = tmp.next
            tmp.next.prev = tmp.prev
            self.bmp.pop(key)
            bucket = tmp.bucket
            if bucket.head == bucket.head.next:
                bucket.prev.next = bucket.next
                bucket.next.prev = bucket.prev
            return tmp


    def LFU(self , operators: List[List[int]], k: int) -> List[int]:
        ret = []
        self.limit = k
        for i in operators:
            if i[1] == -146502911:
                print(i[1])
            if i[0] == 1:
                self.set(i[1], i[2])
            elif i[0] == 2:
                ret.append(self.get(i[1]))
        return ret


class Bucket:
    def __init__(self, times: int):
        """
        定义双向链表桶,用于存放当前次数的Node节点
        :param times: 访问次数
        :return:
        """
        self.times = times
        self.head = BNode(-1, -1, self)
        self.prev = self
        self.next = self

    def push(self, bnode: "BNode"):
        bnode.next = self.head.next
        self.head.next = bnode
        bnode.prev = self.head
        bnode.next.prev = bnode

    def pop(self, bnode: "BNode"):
        bnode.prev.next = bnode.next
        bnode.next.prev = bnode.prev


class BNode:
    def __init__(self, key: int, val: int, bucket: Bucket):
        """
        定义数据节点
        :param key: 传入的key值
        :param val: 传入的val值
        :param bucket: 当前节点所属的桶
        """
        self.bucket = bucket
        self.prev = self
        self.next = self
        self.key = key
        self.val = val

发表于 2022-10-07 22:45:32 回复(0)

问题信息

难度:
2条回答 3727浏览

热门推荐

通过挑战的用户

查看代码