146. LRU 缓存

自己造轮子

class LRUCache {

    // 题根据目要求函数 get 和 put 必须以 O(1) 的平均时间复杂度运行,所以一定需要用到HashMap。
    // 同时,需要删除最久未使用,也就是说需要保留顺序,需要用到队列,并且插入删除复杂度O(1),所以需要用到链表(双向)实现的队列
    // 综上所述,需要设计一个LinkedHashMap这样的类

    // key -> Node(key,val)
    private HashMap<Integer,Node> map;
    // Node(k1,v1) <-> Node(k2,v2)
    private DoubleList cache;
    // 最大容量
    private int cap;


    public LRUCache(int cap){
        this.cap = cap;
        map = new HashMap<>();
        cache = new DoubleList();
    }

    public void put(int key,int value){
        if (map.containsKey(key)){
            // 删除旧数据
            deleteKey(key);
            addRecently(key,value);
            return;
        }
        if (cache.size()==cap){
            removeLeastRecently();
        }

        addRecently(key, value);
    }

    public int get(int key){
        if (!map.containsKey(key)){
            return -1;
        }
        makeRecently(key);
        return map.get(key).val;
    }

    private void removeLeastRecently() {
        Node first = cache.removeFirst();
        map.remove(first.key);
        
    }

    private void deleteKey(int key) {
        Node node = map.get(key);
        map.remove(key);
        cache.remove(node);
    }

    /* 将某个 key 提升为最近使用的 */
    private void makeRecently(int key){
        Node node = map.get(key);
        cache.remove(node);
        cache.addLast(node);
    }

    /* 添加最近使用的元素 */
    private void addRecently(int key,int value){
        Node node = new Node(key, value);
        map.put(key,node);
        cache.addLast(node);
    }

}


class Node {
    public int key, val;
    public Node next, prev;
    public Node(int k, int v) {
        this.key = k;
        this.val = v;
    }
}


class DoubleList{
    // 虚拟头尾节点
    private Node head,tail;
    // 链表元素数
    private int size;

    public DoubleList(){
        head = new Node(0,0);
        tail = new Node(0,0);
        head.next = tail;
        tail.prev = head;
        size = 0;
    }

    // 在尾部添加节点,时间复杂度O(1)
    public void addLast(Node x){
        x.prev = tail.prev;
        x.next = tail;
        tail.prev.next = x;
        tail.prev = x;
        size++;
    }

    // 删除链表中的 x 节点(x 一定存在)
    // 由于是双链表且给的是目标 Node 节点,时间 O(1)
    public void remove(Node x){
        x.prev.next = x.next;
        x.next.prev = x.prev;
        size--;
    }

    // 删除链表中第一个节点,并返回该节点,时间 O(1)
    public Node removeFirst(){
        if (head==tail){
            return null;
        }
        Node first = head.next;
//        head.next = head.next.next;
//        head.next.prev = head;
        remove(first);
        return first;
    }

    public int size(){
        return size;
    }

}

用 Java 的内置类型 LinkedHashMap

class LRUCache {
    int cap;
    LinkedHashMap<Integer, Integer> cache = new LinkedHashMap<>();
    public LRUCache(int capacity) { 
        this.cap = capacity;
    }
    
    public int get(int key) {
        if (!cache.containsKey(key)) {
            return -1;
        }
        // 将 key 变为最近使用
        makeRecently(key);
        return cache.get(key);
    }
    
    public void put(int key, int val) {
        if (cache.containsKey(key)) {
            // 修改 key 的值
            cache.put(key, val);
            // 将 key 变为最近使用
            makeRecently(key);
            return;
        }
        
        if (cache.size() >= this.cap) {
            // 链表头部就是最久未使用的 key
            int oldestKey = cache.keySet().iterator().next();
            cache.remove(oldestKey);
        }
        // 将新的 key 添加链表尾部
        cache.put(key, val);
    }
    
    private void makeRecently(int key) {
        int val = cache.get(key);
        // 删除 key,重新插入到队尾
        cache.remove(key);
        cache.put(key, val);
    }
}

转载:https://leetcode.cn/problems/lru-cache/solutions/12711/lru-ce-lue-xiang-jie-he-shi-xian-by-labuladong/

作者:静默虚空
欢迎任何形式的转载,但请务必注明出处。
限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。

posted @   Chenyi_li  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~
历史上的今天:
2021-10-14 unity商店下载地址
点击右上角即可分享
微信分享提示