LeetCode 热题 HOT 100 (018/100)【宇宙最简单版】

【链表】No. 0146 LRU缓存【中等】👉力扣对应题目指路

希望对你有帮助呀!!💜💜 如有更好理解的思路,欢迎大家留言补充 ~ 一起加油叭 💦
欢迎关注、订阅专栏 【力扣详解】谢谢你的支持!

题目描述:请你设计并实现一个满足 LRU (最近最少使用) 缓存约束的数据结构

  • 实现 LRUCache 类:
    • LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
    • int get(int key)
      • 如果关键字 key 存在于缓存中,则返回关键字的值 value
      • 否则返回 -1
    • void put(int key, int value)
      • 如果关键字 key 已经存在,则变更其数据值 value
      • 如果不存在,则向缓存中插入该组 key-value
      • 如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字
    • 【难点🔥】函数 get 和 put 必须以 O(1) 的平均时间复杂度运行

🔥 思路:哈希表 + 双向链表

  • 因为要根据使用的热度频繁调整存储,所以选用双向链表
    • 本文采用的顺序为:“最近使用的” 放入尾部 tail;“长期未用的” 挤到头部 head
  • 为进一步满足访问 get 的复杂度要求,使用哈希表存储 <key,key 其对应的链表节点>
    • 哈希表的使用可以在 O(1) 时间内,通过 key 找到值 val
  • 示例: 初始化 - put(1,1) - put(2,2) - get(1) - put(3, 3)

    1. 初始化 -------------------------------------------------------------------------------------------------
    2. put(1,1) -------------------------------------------------------------------------------------------------
    3. put(2,2) -------------------------------------------------------------------------------------------------
    4. get(1) --------------------------------------------------------------------------------------------------
    5. put(3, 3) --------------------------------------------------------------------------------------------------

⭐⭐⭐ 题目准备之双向链表插入、删除元素: 一定要先掌握双向链表插入、删除元素 ❗❗❗ 步骤中用 🍀 重点标记出了~


参考如上思路,给出详细步骤如下:

  • 步骤一⭐编写 LRUCache 的 __init__
    • 初始化容量 self.capacity 和当前大小 self.size
    • 初始化双向链表的 self.head, tail
      • 不要忘记链接好 self.head, tail:self.head.next = self.tail;self.tail.last = self.head
    • 初始化所需的哈希表 self.dict
  • 步骤二⭐编写 LRUCache 的 get: 如果关键字 key 存在于缓存中,则返回关键字的值 value;否则返回 -1
    • 通过哈希表的键来进行逻辑判断 key 是否不存在:if not key in self.dict.keys()
    • 存在的话,将对应节点移动至链表尾部并返回关键字的值 value
      • “短路当前节点”【🍀涉及到两个节点 cur.last, cur.next,共更改两条箭头指向】:当前节点的 lastnext 链接
      • “重连当前节点”【🍀涉及到三个节点 tail.last, cur, tail,共更改四条箭头指向】:指向好当前节点的 lastnext
      • 返回 get 结果
  • 步骤三⭐编写 LRUCache 的 put
    • 情况一:如果关键字 key 已经存在,则变更其数据值 value
      • 记得操作一次 get 将改被访问的元素移动到 tail
    • 情况一:如果不存在,则向缓存中插入该组 key-value
      • 如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字
      • 根据 key-value 建立新链表节点 cur 并插入队尾 【🍀涉及到三个节点 tail.last, cur, tail,共更改四条箭头指向】
class ListNode:
    def __init__(self, val=0, next_node=None, last_node=None):
        self.val = val
        self.next = next_node
        self.last = last_node

class LRUCache:
    def __init__(self, capacity: int):  # --------------------- step 1     
        # ---------------------------------------------------- step 1.1
        self.capacity = capacity
        self.size = 0
		# ---------------------------------------------------- step 1.2
        self.head = ListNode()
        self.tail = ListNode()
        self.head.next = self.tail
        self.tail.last = self.head
		# ---------------------------------------------------- step 1.3
        self.dict = {}


    def get(self, key: int) -> int:  # ------------------------ step 2     
        if not key in self.dict.keys():  # ------------------- step 2.1
            return -1
		# ------------------------------------------------- step 2.2.1
        cur = self.dict[key]
        cur.last.next = cur.next
        cur.next.last = cur.last
		# ------------------------------------------------- step 2.2.2
        cur.last = self.tail.last
        cur.next = self.tail
        self.tail.last.next = cur
        self.tail.last = cur
		# ------------------------------------------------- step 2.2.3
        return self.dict[key].val[1]

    def remove_head(self):
        self.head.next = self.head.next.next
        self.head.next.last = self.head

    def put(self, key: int, value: int) -> None:  # ---------- step 3   
    	# --------------------------------------------------- step 3.1
        if key in self.dict.keys():
            self.dict[key].val = [key, value]
            self.get(key)
            return
        #------------------------------------------------- step 3.2.1
        self.size += 1
        if self.size > self.capacity: 
            self.dict.pop(self.head.next.val[0])
            self.remove_head()
            self.size -= 1
		#------------------------------------------------- step 3.2.2
        cur = ListNode([key, value], next_node=self.tail, last_node=self.tail.last)
        self.dict[cur.val[0]] = cur

        self.tail.last.next = cur
        self.tail.last = cur 

希望对你有帮助呀!!💜💜 如有更好理解的思路,欢迎大家留言补充 ~ 一起加油叭 💦
🔥 LeetCode 热题 HOT 100

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值