【LeetCode】【算法】146. LRU缓存

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,则应该逐出最久未使用的关键字。

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

实现思路

LRU本质就是通过一个队列实现的,对于put函数和get函数,最特别的地方在于访问时需要将访问的节点挪到队尾。

  1. 创建ListNode以实现节点。其中包含int key, int value, ListNode next, ListNode prev(双向指针的实现)
  2. 在LRU类中的属性包括:
    I. 虚拟头尾节点ListNode dummyHead, dummyTail;
    II. HashMap用于以O(1)平均复杂度访问到目标节点Map<Integer, ListNode> map;(如果需要遍历整个链表来找目标节点,就不是O(1)的复杂度了)
    III. int capacity表示链表的容量,这是题目需要指定的
    IV. int listLen用于记录当前链表的长度
  3. 初始化LRU类,就是对上面的这些属性做一个初始化,记得虚拟头尾节点的next属性和prev属性需要相连
  4. put方法思路:
    I. 使用map来检查这个节点是否在链表中;
    ① 如果在链表中,则通过map得到这个节点,将该节点从链表中删除,并给改节点赋予新的值;
    ② 如果不在链表中,又分为listLen>=capacity和listLen<capacity的情况(也就是链表容量是否超过指定容量了)
    情况1:链表当前容量已经达到了指定容量,需要删除最久未访问节点(队头),使用虚拟头结点dummyHead来做删除;根据给定的key和value新建一个节点
    情况2:链表当前容量未达到指定容量,则链表长度++,根据给定的key和value新建一个节点
    II. 利用dummyTail将该节点放到链表的最后,并更新map中的内容
  5. get方法思路:
    I. 使用map来检查这个节点是否在链表中,不在返回-1;
    II. 否则利用map来拿到这个节点,将它从链表中移除;并利用dummyTail将该节点放到链表最后,返回该节点的值

实现代码

java 复制代码
class LRUCache {

    class ListNode{
        int key;
        int value;
        ListNode next;
        ListNode prev;

        public ListNode() {

        }

        public ListNode(int key, int value) {
            this.key = key;
            this.value = value;
        }
    }

    ListNode dummyHead;
    ListNode dummyTail;
    Map<Integer, ListNode> map;
    int capacity;
    int listLen;

    public LRUCache(int capacity) {
        map = new HashMap<>();
        dummyHead = new ListNode();
        dummyTail = new ListNode();
        dummyHead.next = dummyTail;
        dummyTail.prev = dummyHead;
        this.capacity = capacity;
        this.listLen = 0;
    }

    public void put(int key, int value) {
        ListNode listNode = null;
        // 如果map里面没有这个key
        if (!map.containsKey(key)){
            // 如果长度已经满了,就移除一个
            if (listLen >= capacity){
                ListNode removeNode = dummyHead.next;
                removeNode.next.prev = removeNode.prev;
                removeNode.prev.next = removeNode.next;
                map.remove(removeNode.key);
            } else {
                listLen++;
            }
            // 新增一个
            listNode = new ListNode(key, value);
        }
        // 如果map里有这个key
        else {
            listNode = map.get(key);
            // 把这个listNode从链表上删除
            ListNode prev_node = listNode.prev;
            ListNode next_node = listNode.next;
            prev_node.next = next_node;
            next_node.prev = prev_node;
            listNode.value = value;
        }
        // 把这个listNode弄到后面去
        ListNode insertPre = dummyTail.prev;
        insertPre.next = listNode;
        listNode.prev = insertPre;
        listNode.next = dummyTail;
        dummyTail.prev = listNode;
        map.put(key, listNode);
    }

    public int get(int key) {
        if (!map.containsKey(key)){
            return -1;
        } else {
            int result = map.get(key).value;
            // 拿到这个Node,移除它
            ListNode listNode = map.get(key);
            // 把这个listNode从链表上删除
            ListNode prev_node = listNode.prev;
            ListNode next_node = listNode.next;
            prev_node.next = next_node;
            next_node.prev = prev_node;
            // 把这个listNode弄到后面去
            ListNode insertPre = dummyTail.prev;
            insertPre.next = listNode;
            listNode.prev = insertPre;
            listNode.next = dummyTail;
            dummyTail.prev = listNode;
            map.put(key, listNode);
            return result;
        }
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */
相关推荐
苏打豆1 小时前
CRISP源码阅读——基于ROS2力矩反馈控制器与速度加速度零空间
c++·线性代数·算法·矩阵·机器人
蛋蛋的就会顺顺的1 小时前
hot100——矩阵
java·数据结构·算法·leetcode·力扣
老歌老听老掉牙2 小时前
麻花钻切屑形态演变的力学机制与临界条件分析
python·算法·钻头
zhangfeng11332 小时前
国产GPU/AI算力芯片现状(修订完整版 · 截至2026年9月
人工智能·算法·ai编程·npu
学代码的CJY3 小时前
从代码出发理解时间复杂度与空间复杂度
数据结构·算法
白帽攻防录3 小时前
SRC 挖洞:WSO2 JWT 算法混淆绕过深度复盘,CVE-2026-5430 不支持的算法怎么变成管理员
网络·算法·安全·网络安全·jwt
小O的算法实验室3 小时前
IEEE TEVC,基于精确与DQN群智能调度方法用于多目标异构USV
算法
可乐ea4 小时前
AI Agent 工具调用准确性评测:选择错误与参数错误分开测
大数据·人工智能·算法·大模型·工具调用·ai智能体·agent评测
上位机妹子4 小时前
C 语言 数组删除指定元素(快慢指针法)
c语言·数据结构·算法
心中有你02145 小时前
【路径规划】A*寻路算法最通俗易懂讲解(C语言完整实现+详细注释)
c语言·开发语言·算法