LeetCode100 LRU缓存思路讲解

思路

这题的关键是同时满足两个要求:

  • O(1) 查找 :所以要用 HashMap。
  • 维护最近使用顺序 :所以要用 双向链表。

只用 HashMap 可以 O(1) 找到 key,但不知道哪个是"最近最少使用"的;

只用链表可以维护顺序,但查找是 O(n)。

所以要把两者结合起来。

数据结构设计

维护一个 双向链表,链表头部表示最近使用的,尾部表示最久未使用的。

同时维护一个 HashMap<Integer, Node>,用来 O(1) 找到某个 key 对应的节点。

  • get(key):

    • 如果 key 不存在,返回 -1。
    • 如果存在,把对应节点移到链表头部,表示最近使用过,然后返回它的值。
  • put(key, value):

    • 如果 key 已存在,更新值,并把节点移到链表头部。
    • 如果 key 不存在:
      • 新建节点,插入链表头部,并放入 map。
      • 如果超过容量,就删除链表尾部节点,同时从 map 中移除。

class LRUCache {

class Node{

int key;

int value;

Node prev;

Node next;

public Node(int key,int value ){

this.key=key;

this.value=value;

}

}

private final int capacity;

private final Map<Integer,Node> map;

private final Node head;

private final Node tail;

public LRUCache(int capacity) {

this.capacity=capacity;

this.map=new HashMap<>();

head=new Node(0,0);

tail=new Node(0,0);

head.next=tail;

tail.prev=head;

}

public int get(int key) {

if(!map.containsKey(key))

return -1;

Node node=map.get(key);

movetohead(node);

return node.value;

}

public void put(int key, int value) {

if(map.containsKey(key)){

Node node=map.get(key);

node.value=value;

movetohead(node);

return;

}

Node node=new Node(key,value);

map.put(key,node);

addtohead(node);

if(map.size()>capacity){

Node lastnode=tail.prev;

removetail();

map.remove(lastnode.key);

return;

}

}

private void addtohead(Node node){

head.next.prev=node;

node.prev=head;

node.next=head.next;

head.next=node;

}

private void removenode(Node node){

node.prev.next=node.next;

node.next.prev=node.prev;

}

private void movetohead(Node node){

removenode(node);

addtohead(node);

}

private Node removetail(){

Node lastnode=tail.prev;

removenode(lastnode);

return lastnode;

}

}

/**

* 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);

*/

相关推荐
北漂人Java1 小时前
基于 Spring AI Alibaba WorkFlow 构建 Java 生产级 AI Agent
java·人工智能·spring
用户112936112192 小时前
编译全绿,上线就崩:MyBatis 五层方法名大小写埋下的坑
java
2501_933923252 小时前
redis:string类型常见命令
数据库·redis·缓存
文丑颜不良啊2 小时前
LeetCode2901~2920题目解析
java·leetcode
码云社区2 小时前
能碳管理系统开发要关注什么?能源数据、统计口径与AI分析的衔接
java·人工智能·ai·能源·能源管理系统·能碳管理系统·能碳管理系统源码
Flynn Liang3 小时前
Agentic 工作流:子代理、Supervisor 与人工介入
java·langchain·多智能体·supervisor·agentic·langchain4j
xys_6783 小时前
JavaSE通关手册:运算符
java·java-ee
starzy19903 小时前
深入理解Scala隐式值:编译期自动装配
开发语言·后端·scala
布莱克6053 小时前
Swift 条件语句详解:从 if 到 switch 的完整指南
开发语言·ssh·swift·switch·条件语句·guard·if
吴可可1233 小时前
ActiveX调用WScript.Shell原理揭秘
开发语言