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)
相关推荐
??tobenewyorker1 小时前
力扣打卡第二十一天 中后遍历+中前遍历 构造二叉树
数据结构·c++·算法·leetcode
凌肖战4 小时前
力扣网C语言编程题:快慢指针来解决 “寻找重复数”
c语言·算法·leetcode
Alfred king17 小时前
面试150 生命游戏
leetcode·游戏·面试·数组
薰衣草23331 天前
一天两道力扣(1)
算法·leetcode·职场和发展
爱coding的橙子1 天前
每日算法刷题Day41 6.28:leetcode前缀和2道题,用时1h20min(要加快)
算法·leetcode·职场和发展
前端拿破轮1 天前
不是吧不是吧,leetcode第一题我就做不出来?😭😭😭
后端·算法·leetcode
前端拿破轮1 天前
😭😭😭看到这个快乐数10s,我就知道快乐不属于我了🤪
算法·leetcode·typescript
今天背单词了吗9801 天前
算法学习笔记:4.KMP 算法——从原理到实战,涵盖 LeetCode 与考研 408 例题
笔记·学习·考研·算法·leetcode·kmp算法
hn小菜鸡2 天前
LeetCode 377.组合总和IV
数据结构·算法·leetcode
亮亮爱刷题11 天前
飞往大厂梦之算法提升-7
数据结构·算法·leetcode·动态规划