146. LRU 缓存

复制代码
https://leetcode.cn/problems/lru-cache/description/?envType=study-plan-v2&envId=top-100-liked
复制代码
最近最久未使用,显然我们需要维护一个使用队列,最近使用过的在队尾,未使用过的靠近队首
并且他要求函数 get 必须以 O(1) 的平均时间复杂度运行显然我们需要用到hash
put 必须以 O(1)的平均时间复杂度运行显然只有链表能做到,并且我们选择双向链表实现
为什么用双向链表而不是单向链表?
将某个节点移动到链表头部或者将链表尾部节点删去,都要用到删除链表中某个节点这个操作。你想要删除链表中的某个节点,需要找到该节点的前驱节点和后继节点。对于寻找后继节点,单向链表和双向链表都能通过 next 指针在O(1)时间内完成;对于寻找前驱节点,单向链表需要从头开始找,也就是要O(n)时间,双向链表可以通过前向指针直接找到,需要O(1)时间。综上,要想在O(1)时间内完成该操作,当然需要双向链表.
java 复制代码
public class LRUCache {
    class Node{
        int key;
        int value;
        Node prev;
        Node next;
        public Node(int key, int value) {
            this.key = key;
            this.value = value;
            this.prev = null;
            this.next = null;
        }
    }
    int capacity;//容量,最大可以存储多少个节点
    int currSize;//当前存储的节点数
    Node head, tail;//头节点,尾节点
    Map<Integer, Node> map = new HashMap<>();//key-value

    public LRUCache(int capacity) {
        this.capacity = capacity;
    }

    public int get(int key) {
        if(map.containsKey(key)){
            Node node = map.get(key);
            removeNode(node);
            return node.value;
        }
        return -1;
    }

    public void put(int key, int value) {
        if(map.containsKey(key)){
            Node node = map.get(key);
            node.value = value;
            removeNode(node);
        } else {
            if(currSize == capacity){
                map.remove(head.key);
                removeNode(head);
                /*if(capacity == 1) {//当前只有一个节点
                    head.key = key;
                    head.value = value;
                } else {//当前节点不是尾节点,则他会被放到尾节点
                    tail.key = key;
                    tail.value = value;
                }*/
                tail.key = key;
                tail.value = value;
                map.put(key, tail);
            } else if(currSize < capacity){
                Node node = new Node(key, value);
                map.put(key, node);
                if(currSize == 0) {//当前没有节点
                    head = node;
                    tail = node;
                } else {
                    tail.next = node;
                    node.prev = tail;
                    tail = node;
                }
                currSize++;
            }

        }
    }

    //将节点node移动到链表尾
    public void removeNode(Node node){
        if(node.next == null) return;
        if(node.prev == null) {//当前节点是头节点
            head = node.next;
            node.next.prev = null;
            node.next = null;
            tail.next = node;
            node.prev = tail;
            tail = node;
        } else {//当前节点不是头节点和尾节点
            node.prev.next = node.next;
            node.next.prev = node.prev;
            node.next = null;
            node.prev = tail;
            tail.next = node;
            tail = node;
        }
    }

    public static void main(String[] args) {
        String[] str = {"LRUCache","put","get","put","get","get"};
        int[][] arr = {{1},{2,1},{2},{3,2},{2},{3}};
        LRUCache lruCache = null;
        List<Integer> list = new ArrayList<>();
        for(int i = 0; i < str.length; i++) {
            if(str[i].equals("LRUCache")) {
                lruCache = new LRUCache(arr[i][0]);
            }
            if(str[i].equals("put")) {
                lruCache.put(arr[i][0], arr[i][1]);
            }
            if(str[i].equals("get")) {
                list.add(lruCache.get(arr[i][0]));
                continue;
            }
            list.add(null);
        }
        System.out.println(list);
    }
}
相关推荐
海鸥-w3 小时前
什么是AOP
java
仍然.4 小时前
Redis---缓存
数据库·redis·缓存
Cc.Y4 小时前
Java零基础入门:可变字符串与包装类:StringBuilder、StringBuffer 与 通讯录管理系统实战
java·开发语言·python
启观川4 小时前
数据结构与算法 -第 3 章 常用算法-动态规划
数据结构·笔记·python·算法
paopaokaka_luck4 小时前
基于springboot+vue的智慧家政管理系统(AI问答、 WebSocket实时沟通、ECharts运营分析、订单规则与服务追踪)
java·javascript·spring boot·数据分析·echarts·mybatis
sm_926787054 小时前
RFID 标签打印的技术实现要点与二次开发实践
java·大数据·前端·c++·编辑器
阿森_dev4 小时前
2027 届毕设选题怎么选:30 个 Java 方向选题的实现难度排序
java·开发语言·spring boot·毕业设计·课程设计
Sarvartha4 小时前
Lambda 表达式和函数式接口
java·开发语言
计算机毕业设计杰瑞4 小时前
【计算机毕设精品】基于SpringBoot的一体化教务与学业质量管理系统的设计与实现,附源码_增删改查_java项目_可完美运行部署_网站项目
java·spring boot·课程设计
colinu5 小时前
C++ 异步任务与线程生命周期:`std::async`、`future`、`thread`、`jthread` 与协作式退出
java·jvm·c++