codeTop100题(3)146. LRU 缓存

140 阅读2分钟

1. 题目链接

146. LRU 缓存

2. 分析

LRU缓存我们可以通过Map + 双向链表来实现,数据结构如图所示:

image.png

  • 调用get方法的时候,直接通过map可以o(1)时间复杂度拿到value
  • 需要删除的时候,直接把tail的pre节点删除就行了
  • 需要更新优先级的时候,就把节点挪到头节点后面

3. 模拟

这种链表类的题目,通过画图来模拟指针的指向过程,可以最大程度得避免我们写代码的时候出现一些奇怪的问题,强烈建议哈。

3.1 初始化

初始化需要做的一些事:

  1. 初始化head 和 tail节点,并连接两个节点
  2. 初始化map和LRU的容量

image.png

3.2 新增节点

这个阶段我们需要做的是将节点插入到head的后面。

下图是这个阶段的开始和结束的两个链表,然而怎么从链表a变成链表b,指针怎么指向,如果我们拉一下指针,然后写一句代码,如果最终的结果没问题,我们就可以确保代码没问题了;当然,如果出现,我改动了指针,最后发现找不到pre了,这种情况下我们也能很快得发现我们调整指针的顺序是哪里有问题,最终进行fix。 image.png

3.3 get方法调用

这里我们模拟一下存在两个节点,然后get靠后的一个节点的情况,首先需要把这个节点从链表里面移出,然后放到head的后面去(第二步复用上面的逻辑)。如下图所示:

image.png

3.4 超过容量删除

这一步咱们可以复用上一步的删除节点的逻辑,然后记得从map里面删掉去。

4. 代码

最终我们可以得到我们的代码,如下:

import java.util.HashMap;
import java.util.Map;

public class LRUCache {
    Map<Integer, MyNode> map;

    MyNode head;
    MyNode tail;

    int capacity;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        map = new HashMap<>();
        head = new MyNode();
        head.key = -999;
        head.value = -999;
        tail = new MyNode();
        tail.key = 999;
        tail.value = 999;

        head.next = tail;
        tail.pre = head;
    }

    public int get(int key) {
        MyNode myNode = map.get(key);
        if (null == myNode) {
            return -1;
        }
        removeNode(myNode);
        insertHead(myNode);
//        System.out.println(myNode.value);
        return myNode.value;
    }


    public void put(int key, int value) {
        MyNode myNode = map.get(key);
        if (null == myNode) {
            myNode = new MyNode();
            myNode.key = key;
            myNode.value = value;
            map.put(key, myNode);
            insertHead(myNode);
            if (capacity < map.size()) {
                map.remove(tail.pre.key);
                removeNode(tail.pre);
            }
        } else {
            myNode.value = value;
            removeNode(myNode);
            insertHead(myNode);
        }
    }

    private void removeNode(MyNode myNode) {
        myNode.pre.next = myNode.next;
        myNode.next.pre = myNode.pre;
    }

    private void insertHead(MyNode myNode) {
        myNode.next = head.next;
        head.next.pre = myNode;
        head.next = myNode;
        myNode.pre = head;
    }
/*

    public static void main(String[] args) {
        LRUCache lruCache = new LRUCache(2);
        lruCache.put(1,1);
        lruCache.put(2,2);
        lruCache.get(1);
        lruCache.put(3,3);

        lruCache.get(2);
        lruCache.put(4,4);

        lruCache.get(1);

        lruCache.get(3);

        lruCache.get(4);
    }*/
}

class MyNode {
    int key;
    int value;
    MyNode pre = null;
    MyNode next = null;
}