146.LRU缓存|字典+双向链表

在这里插入图片描述
在这里插入图片描述

  • 常数的时间复杂度:用hash字典
  • 最久没用的关键字:要记录使用顺序,用队列
  • 这里有问题:如果get()取得的是队列中间的关键字,此时要将其移到最后。时间复杂度不会是常数。单链表移动也不会是常数的时间复杂度,要用双向链表。
class LRUCache: # 不行的代码
    def __init__(self, capacity: int):
        self.capacity = capacity
        self.dicts = collections.defaultdict(lambda:-1) # 默认-1
        self.queue = []
        self.count = 0


    def get(self, key: int) -> int:
        
        return self.dicts[key] # 没被put就默认返回-1


    def put(self, key: int, value: int) -> None:
        self.dicts[key] = value
        self.count += 1
        self.queue.insert(0, key)
        if self.count > self.capacity:
            tmpkey = self.queue.pop()
            print(key)
            self.count -= 1
            self.dicts[tmpkey] = -1
     
# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)
  • 双向链表+hash字典
class ListNode: # Ok的代码
    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: int):
        self.dicts = {}
        self.capacity = capacity
        self.head = ListNode()
        self.tail = ListNode(prev=self.head)
        self.head.next = self.tail 
    
    def move_to_end(self, key): # 根据键找到对应的链表结点
        node = self.dicts[key]
        # 将断点两边的结点连接上
        if node.next and node.prev:# 如果是已经在链表中,还需断开
            node.prev.next = node.next
            node.next.prev = node.prev
        # 将该节点插到最后的结点前
        # 1.该节点连上去
        node.next = self.tail
        node.prev = self.tail.prev
        # 2.该结点两边的连上
        self.tail.prev.next = node
        self.tail.prev = node


    def get(self, key: int) -> int:
        node = self.dicts.get(key, None) # 如果不存在返回None
        if node:# 存在
            # 将其移到最后去
            self.move_to_end(key)
            return node.value
        else: 
            return -1

    def put(self, key: int, value: int) -> None:
        if key in self.dicts: # 如果已存在,更新value
            self.dicts[key].value = value
        else: # 不存在,插入
            newnode = ListNode(key=key, value=value)
            self.dicts[key] = newnode

        # 移到最后,更新最新使用过
        self.move_to_end(key)

        if len(self.dicts) > self.capacity: # 超过容量,需删除最前面的最久没使用的结点
            # 找到要删除的结点
            node = self.head.next
            # 删除字典中的该键值对
            
            self.dicts.pop(node.key) # 这里就是node也要保存key的原因
            # 删除双向链表中的该结点
            self.head.next = node.next
            node.next.prev = self.head
       
# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)

参考链接:数据结构分析,Python 哈希 + 双向链表实现(代码注释多)
如果比较模糊,建议动手画下。只要思路有了,实现就不是很难。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值