LRU设计, 双向链表 + HashMap<Integer, DBNode>
/**
* Runtime: 24 ms, faster than 17.52%
* Memory Usage: 57.2 MB, less than 5.09%
*/
class LRUCache {
class DBNode { // 双向链表节点
int key, val;
DBNode pre, next;
public DBNode(int key, int val) {
this.key = key;
this.val = val;
}
}
class DBLinkedList { // 双向链表
private DBNode sentinel, tail;
private int size;
public DBLinkedList() {
sentinel = new DBNode(0, 0);
tail = new DBNode(0, 0);
sentinel.next = tail;
tail.pre = sentinel;
}
public int size() {
return size;
}
public void addFirst(DBNode node) {
node.next = sentinel.next;
node.pre = sentinel;
sentinel.next = node;
node.next.pre = node;
size++;
}
public int removeLast() {
int res = tail.pre.key;
tail.pre = tail.pre.pre;
tail.pre.next = tail;
size--;
return res;
}
public void remove(DBNode node) {
node.pre.next = node.next;
node.next.pre = node.pre;
size--;
}
}
int capacity;
HashMap<Integer, DBNode> map;
DBLinkedList list;
public LRUCache(int capacity) {
this.capacity = capacity;
map = new HashMap<>();
list = new DBLinkedList();
}
public int get(int key) {
if (!map.containsKey(key)) {
return -1;
}
int res = map.get(key).val;
put(key, res); // 更新节点在list中的位置
return res;
}
public void put(int key, int value) {
if (map.containsKey(key)) { // 更新
DBNode node = map.get(key);
node.val = value;
list.remove(node);
list.addFirst(node);
} else { // 加入新的node
DBNode node = new DBNode(key, value);
if (list.size() == capacity) {
int removedKey = list.removeLast();
map.remove(removedKey);
}
list.addFirst(node);
map.put(key, node);
}
}
}
/**
* 第一次复习
* 没有像上次一样封装一个很完整的DBList类,导致代码冗余较多,面向对象思想不完善(比如可以直接封装一个addFirst函数,后面就不用重复两遍这段代码)
* 后来封装了写出来和上一段一样的代码,不赘述
* Runtime: 47 ms, faster than 63.30%
* Memory Usage: 112.1 MB, less than 34.01%
*/
class LRUCache {
HashMap<Integer, DBListNode> map; // map key and the corresponding val
DBListNode head, tail; // the start and end of the two side list
int capacity, size; // the max size and the current size
class DBListNode {
int key, val;
DBListNode pre, next;
DBListNode(int key, int val) {
this.key = key;
this.val = val;
}
}
public LRUCache(int capacity) {
this.capacity = capacity;
head = new DBListNode(-1, -1);
tail = new DBListNode(-1, -1);
head.next = tail;
tail.pre = head;
map = new HashMap();
}
public int get(int key) {
if (!map.containsKey(key)) { // the key dose not exist
return -1;
}
int value = map.get(key).val;
put(key, value);
return value;
}
public void put(int key, int value) {
if (map.containsKey(key)) {
DBListNode curr = map.get(key);
// update curr's val
curr.val = value;
// move curr to the first node
curr.next.pre = curr.pre;
curr.pre.next = curr.next;
curr.next = head.next;
curr.pre = head;
head.next = curr;
curr.next.pre = curr;
} else {
if (size == capacity) { // full cache, add a new node to the first and remove the last node
// remove the last node
map.remove(tail.pre.key);
tail.pre = tail.pre.pre;
tail.pre.next = tail;
// add a new node to the first
DBListNode curr = new DBListNode(key, value);
curr.pre = head;
curr.next = head.next;
head.next.pre = curr;
head.next = curr;
map.put(key, curr);
} else { // space available for the new node, just add a new node to the first
DBListNode curr = new DBListNode(key, value);
curr.pre = head;
curr.next = head.next;
head.next.pre = curr;
head.next = curr;
map.put(key, curr);
size++;
}
}
}
}