# 手撕一個LRU Cache

### LeetCode 146 - LRU Cache

Design a data structure that follows the constraints of a Least Recently Used (LRU) cache.
Implement the LRUCache class:

• LRUCache(int capacity) Initialize the LRU cache with positive size capacity.
• int get(int key) Return the value of the key if the key exists, otherwise return -1.
• void put(int key, int value) Update the value of the key if the key exists. Otherwise, add the key-value pair to the cache. If the number of keys exceeds the capacity from this operation, evict the least recently used key.

Could you do get and put in O(1) time complexity?

• 什麼數據結構能夠滿足在O(1)時間內存取數據？——哈希表。
• 什麼數據結構能夠記錄元素進入緩存的順序？——數組或鏈表。但是爲了與上一個條件配合，只有雙端鏈表能滿足。

Java代碼如下。注意這裏採用了頭插法，亦即鏈表頭部的元素最新，鏈表尾部的元素最舊。在執行get/put操作時，如果key對應的元素已經存在，就需要將這個最近使用的元素從鏈表中移除，再插回頭部。如果超過了緩存容量，就從鏈表尾部淘汰元素。

class LRUCache {
private class ListNode {
private int key;
private int value;
private ListNode prev, next;

public ListNode() {}

public ListNode(int key, int value) {
this.key = key;
this.value = value;
}
}

private Map<Integer, ListNode> container;
private int capacity, size;

public LRUCache(int capacity) {
this.container = new HashMap<>();
this.head = this.tail = new ListNode();
this.capacity = capacity;
this.size = 0;
}

private void insertNode(ListNode node) {
}

private void deleteNode(ListNode node) {
ListNode nPrev = node.prev, nNext = node.next;
nPrev.next = nNext;
nNext.prev = nPrev;
node.prev = node.next = null;
}

public int get(int key) {
ListNode data = container.get(key);
if (data == null) {
return -1;
}

deleteNode(data);
insertNode(data);
return data.value;
}

public void put(int key, int value) {
ListNode data = container.get(key);
if (data == null) {
if (size < capacity) {
size++;
} else {
ListNode leastRecent = tail.prev;
container.remove(leastRecent.key);
deleteNode(leastRecent);
}

ListNode newNode = new ListNode(key, value);
insertNode(newNode);
container.put(key, newNode);
} else {
data.value = value;
deleteNode(data);
insertNode(data);
}
}
}

class LRUCache extends LinkedHashMap<Integer, Integer> {
private int capacity;

public LRUCache(int capacity) {
super(capacity, 0.75f, true);
this.capacity = capacity;
}

@Override
protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
return size() > capacity;
}

public int get(int key) {
return super.getOrDefault(key, -1);
}

public void put(int key, int value) {
super.put(key, value);
}
}