算是LeetCode上面一道非常著名的题目了,原理就是手写一个双向链表,然后和HashMap组合在一起最终实现LRU算法
class LRUCache {
HashMap<Integer, Node> map;
DoubleLinkedList cache;
int cap;
public LRUCache(int capacity) {
// map中的key只是作为唯一标识符,用于快速地找到value,value则存储的是双向链表的节点
map = new HashMap<>();
cache = new DoubleLinkedList();
// 指定缓存的大小
cap = capacity;
}
public int get(int key) {
if (map.containsKey(key)) {
// 通过key在O(1)内找到value,这个value是节点,val代表的是value这个节点的值,这点一直没搞清楚
int val = map.get(key).value;
put(key, val);
// get方法最后必须返回它的值,其实就那道题的测试用例看起来,val和key是同一个
return val;
}
return -1;
}
public void put(int key, int value) {
// 没有对Node进行传参的话,需要new这个对象
Node newNode = new Node(key, value);
if (map.containsKey(key)) {
cache.delete(map.get(key));
cache.addHead(newNode);
map.put(key, newNode);
} else {
if (map.size() == cap) {
//deleteLast
// 这里要注意的就是删除的是最后一个,map中remove也也是它的key,这也是为什么删除的返回值需要为int
int k = cache.deleteLast();
// map remove
map.remove(k);
}
// addFirst
cache.addHead(newNode);
// add to map
map.put(key, newNode);
}
}
class DoubleLinkedList {
Node head;
Node tail;
public DoubleLinkedList() {
head = new Node(0, 0);
tail = new Node(0, 0);
head.next = tail;
tail.prev = head;
}
public void addHead(Node node) {
node.next = head.next;
node.prev = head;
// 这里要注意,如果先指定了head.next,那么head.next.prev就会空了
head.next.prev = node;
head.next = node;
}
public int delete(Node node) {
int key = node.key;
node.next.prev = node.prev;
node.prev.next = node.next;
return key;
}
public int deleteLast() {
if(head.next==tail){
return -1;
}
return delete(tail.prev);
}
}
class Node {
public int key;
public int value;
public Node prev;
public Node next;
public Node(int key, int value) {
this.key = key;
this.value = value;
}
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache obj = new LRUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/