035LRU缓存

LRU缓存

题目链接:https://leetcode.cn/problems/lru-cache/description/?envType=study-plan-v2\&envId=top-100-liked

我的解答:

复制代码

分析:自己没什么思路。

看了官方题解后的解答:

复制代码
//哈希表+双向链表
//时间复杂度:对于get和put,时间复杂度均为O(1)
//空间复杂度:O(capacity),哈希表和双向链表最多存储capacity+3个元素
class ListNode{
    int key;
    int value;
    ListNode last;
    ListNode next;
    ListNode(){};
    ListNode(int key, int value, ListNode last, ListNode next){
        this.key = key;
        this.value = value;
        this.last = last;
        this.next = next;
    }
}
int capacity;
int size;
Map<Integer,ListNode> map;
ListNode dummyHead;
ListNode dummyTail;
public LRUCache(int capacity) {
    this.capacity = capacity;
    this.size = 0;
    map = new HashMap<Integer,ListNode>(capacity);
    dummyHead = new ListNode();
    dummyTail = new ListNode();
    dummyHead.next = dummyTail;
    dummyTail.last = dummyHead;
}

public int get(int key) {
    if(!map.containsKey(key)){
        return -1;
    }
    ListNode node = map.get(key);
    //移动至头部
    removeToHead(node);
    return node.value;
}

public void put(int key, int value) {
    if(map.containsKey(key)){
        ListNode node = map.get(key);
        node.value = value;
        //移动至头部
        removeToHead(node);
    }
    else{
        ListNode node = new ListNode(key,value,dummyHead,dummyHead.next);
        dummyHead.next = node;
        node.next.last = node;
        map.put(key,node);
        size++;
        if(size>capacity){
            map.remove(dummyTail.last.key);
            removeTail();
            size--;
        }
    }
}
//将节点移动至链表头部
public void removeToHead(ListNode node){
    node.last.next = node.next;
    node.next.last = node.last;
    node.next = dummyHead.next;
    node.last = dummyHead;
    dummyHead.next = node;
    node.next.last = node;
}
//删除尾节点
public void removeTail(){
    dummyTail.last = dummyTail.last.last;
    dummyTail.last.next = dummyTail;
}

分析:

​ 1、本题采用哈希表+双向链表,哈希表存储key与双向链表之间的映射关系,双向链表维护了访问顺序,靠近链表头部的键值对是最近使用的,靠近尾部的键值对是最久未使用的,双向链表在头部引入了一个虚拟头节点,在尾部引入了一个虚拟尾节点,可以避免边界情况的判断。

​ 2、解题思路:在Java中,存在一种已经包装好的数据结构可以实现题目要求,这种数据结构就是LinkedHashMap,即哈希表+双向链表。

​ 3、注意:第一,当超出容量时,我们不仅需要移除链表尾节点,还需同步删除哈希表对应的键值对;第二,每次的get操作也要同时更新链表之间的顺序关系。

总结

  • 本题主要是模拟Java中的LinkedHashMap,即采用哈希表+双向链表实现编码。靠近链表头部的键值对是最近使用的,靠近尾部的键值对是最久未使用的,哈希表维护了key与链表节点之间的映射关系,可以通过哈希表快速定位对应的节点位置,从而在O(1)的时间复杂度下实现LRU(最近最少使用)缓存。
相关推荐
未秃头的程序猿38 分钟前
Java 26正式发布!这3个新特性,让代码量直接减半
java·后端·面试
用户298698530141 小时前
Word 文档文本查找与替换的 Java 实现方案
java·后端
阿哉1 小时前
Nacos 服务发现源码:藏在背后的两套事件机制,90%的人只讲了一半
java
咖啡八杯1 小时前
GoF设计模式——命令模式
java·设计模式·架构
AI人工智能_电脑小能手2 小时前
【大白话说Java面试题 第125题】【并发篇】第25题:说说 Java 线程的中断机制
java·后端·面试
Java内核笔记2 小时前
Spring Security 源码解析(六)无状态 JWT 实践:Session 共享与自定义过滤器
java·后端
荣码2 小时前
LangGraph多Agent协作:3个Agent干活比1个强,但我踩了4个坑
java·python
唐青枫3 小时前
Java 虚拟线程实战指南:从 Thread API 到 Spring Boot 高并发应用
java
白鲸开源19 小时前
Apache SeaTunnel Zeta Engine 的 Basic Auth 是怎么工作的?
java·vue.js·github
白鲸开源19 小时前
一文读懂DolphinScheduler插件机制:如何轻松扩展任务类型与数据源
java·架构·github