1. 题目链接
2. 分析
LRU缓存我们可以通过Map + 双向链表来实现,数据结构如图所示:
- 调用get方法的时候,直接通过map可以o(1)时间复杂度拿到value
- 需要删除的时候,直接把tail的pre节点删除就行了
- 需要更新优先级的时候,就把节点挪到头节点后面
3. 模拟
这种链表类的题目,通过画图来模拟指针的指向过程,可以最大程度得避免我们写代码的时候出现一些奇怪的问题,强烈建议哈。
3.1 初始化
初始化需要做的一些事:
- 初始化head 和 tail节点,并连接两个节点
- 初始化map和LRU的容量
3.2 新增节点
这个阶段我们需要做的是将节点插入到head的后面。
下图是这个阶段的开始和结束的两个链表,然而怎么从链表a变成链表b,指针怎么指向,如果我们拉一下指针,然后写一句代码,如果最终的结果没问题,我们就可以确保代码没问题了;当然,如果出现,我改动了指针,最后发现找不到pre了,这种情况下我们也能很快得发现我们调整指针的顺序是哪里有问题,最终进行fix。
3.3 get方法调用
这里我们模拟一下存在两个节点,然后get靠后的一个节点的情况,首先需要把这个节点从链表里面移出,然后放到head的后面去(第二步复用上面的逻辑)。如下图所示:
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;
}