【Hot100】LeetCode—146. LRU 缓存

目录

  • 1-思路
    • [1-1 LRU知识点](#1-1 LRU知识点)
    • [1-2 实现思路](#1-2 实现思路)
      • LRU的子数据结构
        • [① 双向链表 DLinkedNode 结点定义](#① 双向链表 DLinkedNode 结点定义)
        • [② 其他字段](#② 其他字段)
      • LRU实现的方法
        • [① 初始化------LRUCache中初始化](#① 初始化——LRUCache中初始化)
        • [② public int get(int key) 取元素方法](#② public int get(int key) 取元素方法)
        • [③ public void put(int key, int value) 存元素方法](#③ public void put(int key, int value) 存元素方法)
  • 2-实现
    • [⭐146. LRU 缓存------题解思路](#⭐146. LRU 缓存——题解思路)
  • [3- ACM实现](#3- ACM实现)


1-思路

1-1 LRU知识点

  • LRU :最近最少使用算法,如果经常请求的数据不会被淘汰,会被淘汰的是最近最少请求的数据。
  • 热门数据会往上排列
  • 看到 LRU,就想到 LRU 对应的数据结构 ------> HashMap + 双向链表(DLinkedNode)

1-2 实现思路

LRU 算法的具体步骤

  • 1- 头插: 新数据直接插入到列表头部
  • 2- 移动到头: 缓存数据被命中,将数据移动到列表头部
  • 3- 删除尾部: 缓存已经满的时候,移除列表尾部数据

LRU的子数据结构

① 双向链表 DLinkedNode 结点定义
  • 包含 keyvaluekey 就是 HashMapkey
java 复制代码
class DLinkedNode{
    int key;
    int value;
    DLinkedNode pre;
    DLinkedNode next;
    DLinkedNode(){}
    DLinkedNode(int k,int v){key = k; value = v;}
}
② 其他字段
  • cache :缓存 Map<Integer,DLinkedNode> :key 放 key,value 放值
  • size:当前缓存中的元素个数
  • capacity:缓存的容量
  • DLinkedNode head,tail:定义双向链表的头尾结点
java 复制代码
Map<Integer,DLinkedNode> cache = new HashMap<Integer,DLinkedNode>();
int size;
int capacity;
DLinkedNode head,tail;

LRU实现的方法

① 初始化------LRUCache中初始化
  • 根据 capacity 传入的容量进行初始化
java 复制代码
    public LRUCache(int capacity) {
        this.size = 0;
        this.capacity = capacity;
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head.next = tail;
        tail.pre = head;
    }
② public int get(int key) 取元素方法

获取元素涉及到的方法如下

  • 1- public int get(int key)
    • 通过 key 获取元素,直接使用 mapget方法
    • 若不存在,返回 -1
    • 若存在,先将其 moveToHead(DLinkedNode node) 再返回
  • 2- moveToHead(DLinkedNode node)
    • private DLinkedNode remove(DLinkedNode node):先删除node元素
    • private void addToHead(DLinkedNode node)再添加到头
  • 3- remove(DLinkedNode node)
    • 双链表 删除 node 结点
  • 4- addToHead(DLinkedNode node)
    • 双链表头插

③ public void put(int key, int value) 存元素方法
  • 添加元素思考:
    • 当前元素不存在,直接添加,添加过程中需要判断缓存是否已满
    • 若存在,更新 value 即可

2-实现

⭐146. LRU 缓存------题解思路


java 复制代码
class LRUCache {

    public class DLinkedNode{
        int key;
        int val;
        DLinkedNode pre;
        DLinkedNode next;
        DLinkedNode(){}
        DLinkedNode(int k,int v){
            key = k;
            val = v;
        }
    }
    // 定义 LRU 所需要的变量
    HashMap<Integer,DLinkedNode> cache = new HashMap<>();
    int capacity;
    int size;
    DLinkedNode head,tail;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.size = 0;
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head.next = tail;
        tail.pre = head;
    }
    
    public int get(int key) {
        // get 元素
        DLinkedNode node = cache.get(key);
        if(node==null){
            return -1;
        }
        // 双链表操作
        moveToHead(node);
        return node.val;
    }

    private void moveToHead(DLinkedNode node){
        remove(node);
        addToHead(node);
    }

    private void remove(DLinkedNode node){
        node.pre.next = node.next;
        node.next.pre = node.pre;
    }
    
    private void addToHead(DLinkedNode node){
        node.next = head.next;
        head.next.pre = node;
        head.next = node;
        node.pre = head;
    }

    public void put(int key, int value) {
        // 要判断是更新还是新增
        DLinkedNode node = cache.get(key);
        if(node==null){
            DLinkedNode newNode = new DLinkedNode(key,value);
            cache.put(key,newNode);
            size++;
            addToHead(newNode);
            if(size>capacity){
                DLinkedNode last = removeLast();
                cache.remove(last.key);
                size--;
            }
        }else{
            node.val = value;
            moveToHead(node);
        }
    }

    public DLinkedNode removeLast(){
        DLinkedNode last = tail.pre;
        remove(last);
        return last;
    }
}

3- ACM实现

java 复制代码
import java.util.HashMap;
import java.util.Scanner;


public class LRUCache {


    // 1- 定义数据
    class DLinkedNode{
        int key;
        int value;
        DLinkedNode pre;
        DLinkedNode next;
        DLinkedNode(){}
        DLinkedNode(int k,int v){
            key = k;
            value = v;
        }
    }
    int size;
    int capacity;
    DLinkedNode head,tail;
    HashMap<Integer,DLinkedNode> cache = new HashMap<>();

    // 2- 初始化
    public LRUCache(int capacity){
        this.capacity = capacity;
        this.size = 0;
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head.next = tail;
        tail.pre = head;
    }


    // 3- 实现 LRU 的get方法
    public int get(int key){
        DLinkedNode node = cache.get(key);
        if(node== null){
            return -1;
        }
        moveToHead(node);
        return node.value;
    }

    private void moveToHead(DLinkedNode node){
        remove(node);
        addToHead(node);
    }

    private void remove(DLinkedNode node){
        node.pre.next = node.next;
        node.next.pre = node.pre;
    }

    private void addToHead(DLinkedNode node){
        node.next = head.next;
        head.next.pre = node;
        head.next = node;
        node.pre = head;
    }

    // 4- 实现 LRU 的put方法
    public void put(int key,int value){
        DLinkedNode node = cache.get(key);
        if(node==null){
            node = new DLinkedNode(key,value);
            cache.put(key,node);
            addToHead(node);
            size++;
            if(size>capacity){
                DLinkedNode ttail = removeTail();
                cache.remove(ttail.key);
                size--;
            }
        }
    }

    private DLinkedNode removeTail(){
        DLinkedNode node = tail.pre;
        remove(node);
        return node;
    }


    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("输入cache缓存容量capacity");
        int capacity = scanner.nextInt();
        LRUCache cache = new LRUCache(capacity);
        while (scanner.hasNext()) {
            String operation = scanner.next();
            if (operation.equals("get")) {
                int key = scanner.nextInt();
                System.out.println(cache.get(key));
            } else if (operation.equals("put")) {
                int key = scanner.nextInt();
                int value = scanner.nextInt();
                cache.put(key, value);
            }
        }
        scanner.close();
    }
}

相关推荐
大明者省1 小时前
WSL2 Ubuntu22.04 GPU训练环境配置指南
人工智能·算法·计算机视觉
m0_380743872 小时前
给大模型调用加一层本地缓存,让重复请求直接命中磁盘
缓存
白狐_7983 小时前
408数据结构第8章:排序②——性质对比秒杀、场景选择与外部排序
java·数据结构·算法
zander2583 小时前
LeetCode 84:柱状图中的最大矩形——单调栈如何确定左右边界
java·数据结构·算法
Shell运维手记4 小时前
Linux 常用基础命令学习笔记
linux·运维·笔记·学习·算法·github
杨航 AI4 小时前
O(n log n):线性对数原理拆解 这个是排序算法的黄金复杂度之一。
算法·排序算法
FakeOccupational4 小时前
【电路笔记 STM32】Cortex-M7 内核上的数据缓存(D-Cache)结构+MPU+DMA&Cache+STM32CubeMX配置
笔记·stm32·缓存
船厂电气自动化ai大模型5 小时前
AI大模型与数学 第32课 函数凹凸性与二阶导数:拐点求解、凹凸区间计算(10道二阶导数计算题)
数据结构·人工智能·python·深度学习·算法
旖旎夜光5 小时前
LeetCode 3:无重复字符的最长子串(滑动窗口) —— 题解
数据结构·c++·算法·leetcode·滑动窗口
叠层归一研究院6 小时前
AGI 系统(十一):二阶网络 — 二阶递归 × 多主体 (元符号网络)
开发语言·人工智能·算法·php·agi