leetcode-146. LRU 缓存

题目描述

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

实现 LRUCache 类:

  • LRUCache(int capacity)正整数 作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1
  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

函数 getput 必须以 O(1) 的平均时间复杂度运行。

示例:

复制代码
输入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1);    // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2);    // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1);    // 返回 -1 (未找到)
lRUCache.get(3);    // 返回 3
lRUCache.get(4);    // 返回 4

思路

使用双向链表来完成,参考:. - 力扣(LeetCode)

1)需要创建一个链表结构【key,value,prev,next】

2)初始化:容器的容量,hash字典,双向链表的构建

3)定义一个将节点移动到末尾的函数【最新被访问的节点都放在队尾】

3.1)从hash字典里读取这个节点

3.2)缝合这个节点的前后

3.3)这个节点插入到尾部节点之前

4)get操作:如果key值在hash字典里,就先移动到队尾;从hash字典里获取key的值,如果不等于-1就返回其value

5)put操作:如果key在hash字典里,就更新该key在hash字典里的value,并将其移动到队尾;如果没在过,就先看是否当前的hash字典已经满足容量里,如果满足:则移除头节点后面的节点,之后进行缝合;

5.1)新建一个节点,放入hash字典中;将新节点插入到尾部节点之前

ps:一般插入操作都是4步,node.next,node.prev;之后插入的位置前节点指向该节点,后面的节点指向该节点

python 复制代码
class ListNode:
    def __init__(self, key=None, value=None):
        self.key = key
        self.value = value
        self.prev = None
        self.next = None

class LRUCache(object):

    def __init__(self, capacity):
        """
        :type capacity: int
        """
        self.capacity = capacity
        self.hashmap = {}
        self.head = ListNode()
        self.tail = ListNode()
        self.head.next = self.tail
        self.tail.prev = self.head

    def move_node_to_tail(self, key):
        node = self.hashmap[key]
        node.prev.next = node.next
        node.next.prev = node.prev

        node.next = self.tail
        node.prev = self.tail.prev
        self.tail.prev.next = node
        self.tail.prev = node 

    def get(self, key):
        """
        :type key: int
        :rtype: int
        """
        if key in self.hashmap:
            self.move_node_to_tail(key)
        res = self.hashmap.get(key,-1)
        if res == -1:
            return res 
        else:
            return res.value

    def put(self, key, value):
        """
        :type key: int
        :type value: int
        :rtype: None
        """
        if key in self.hashmap:
            self.hashmap[key].value = value
            self.move_node_to_tail(key)
        else:
            if len(self.hashmap) == self.capacity:
                self.hashmap.pop(self.head.next.key)
                self.head.next = self.head.next.next
                self.head.next.prev = self.head
            new = ListNode(key, value)
            self.hashmap[key] = new 
            new.next = self.tail
            new.prev = self.tail.prev
            self.tail.prev.next = new
            self.tail.prev = new

# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)
相关推荐
西几1 小时前
代码训练营 day48|LeetCode 300,LeetCode 674,LeetCode 718
c++·算法·leetcode
liuyang-neu1 小时前
力扣第420周赛 中等 3324. 出现在屏幕上的字符串序列
java·算法·leetcode
小卡皮巴拉2 小时前
【力扣刷题实战】相同的树
c语言·算法·leetcode·二叉树·递归
潇雷2 小时前
算法Day12|226-翻转二叉树;101-对称二叉树;104-二叉树最大深度;111-二叉树最小深度
java·算法·leetcode
韭菜盖饭3 小时前
LeetCode每日一题3211---生成不含相邻零的二进制字符串
数据结构·算法·leetcode
旋转的油纸伞4 小时前
大模型,多模态大模型面试【LoRA,分类,动静态数据类型,DDPM,ControlNet,IP-Adapter, Stable Diffusion】
算法·leetcode·面试·职场和发展·散列表
DdddJMs__1356 小时前
C语言 | Leetcode C语言题解之第517题超级洗衣机
c语言·leetcode·题解
Wils0nEdwards7 小时前
Leetcode 合并 K 个升序链表
算法·leetcode·链表
Tisfy7 小时前
LeetCode 3211.生成不含相邻零的二进制字符串:二进制枚举+位运算优化
算法·leetcode·二进制·题解·枚举·位运算