---
tags: leetcode
---
# [146. LRU Cache](https://leetcode.com/problems/lru-cache/)
---
# My Solution
## The Key Idea for Solving This Coding Question
用雙向環狀鏈結串列 (Circular Doubly Linked List) 串聯所有的 key-value pair。並將最近用到的 key-value pair 放在雙向環狀鏈結串列的串列首。
最近用到的 key-value pair 大致列舉如下:
* 用 `get` 調用的 key-value pair
* 新增的 key-value pair
* 被更新 value 的 key
在這個問題中用雙向環狀鏈結串列可以自然地把 Least Recently Used (LRU) 放到雙向環狀鏈結串列的末端。
再搭配 `unordered_map` 可以用 key 以 $O(1)$ 的時間複雜度找到雙向環狀鏈結串列中相對應的節點。
## C++ Code 1
```cpp=
struct Node {
int key;
int val;
Node *prev;
Node *next;
Node() :key(0), val(0), prev(nullptr), next(nullptr) {}
Node(int key, int val) : key(key), val(val), prev(nullptr), next(nullptr) {}
};
class LRUCache {
public:
LRUCache(int capacity) : capacity(capacity), size(0) {
head = new Node();
head->next = head;
head->prev = head;
}
int get(int key) {
auto iter = keyToNode.find(key);
if (iter == keyToNode.end()) {
// key doesn't exixt.
return -1;
}
// key exists.
Node *node = iter->second;
remove(node);
addAtHead(node);
return node->val;
}
void put(int key, int value) {
auto iter = keyToNode.find(key);
if (iter == keyToNode.end()) {
// key doesn't exist.
if (size < capacity) {
// LRU cache is not full.
Node *newNode = new Node(key, value);
keyToNode[key] = newNode;
addAtHead(newNode);
++size;
return;
}
// LRU cache is full.
Node *lru = head->prev;
remove(lru);
keyToNode.erase(keyToNode.find(lru->key));
delete lru;
Node *newNode = new Node(key, value);
keyToNode[key] = newNode;
addAtHead(newNode);
return;
}
// key exists.
Node *node = iter->second;
remove(node);
node->val = value;
addAtHead(node);
}
private:
int capacity;
int size;
Node *head;
unordered_map<int, Node *> keyToNode;
void remove(Node *node) {
node->prev->next = node->next;
node->next->prev = node->prev;
node->next = node;
node->prev = node;
}
void addAtHead(Node *node) {
node->prev = head;
node->next = head->next;
head->next->prev = node;
head->next = node;
}
};
/**
* 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);
*/
```
## C++ Code 2
```cpp=
struct Node {
int key;
int val;
Node *prev;
Node *next;
Node() : key(-1), val(-1), prev(nullptr), next(nullptr) {}
Node(int key, int val) : key(key), val(val), prev(nullptr), next(nullptr) {}
};
class LRUCache {
public:
LRUCache(int capacity) {
cap = capacity;
len = 0;
head = new Node();
head->next = head;
head->prev = head;
}
int get(int key) {
auto iter = keyToNode.find(key);
if (iter == keyToNode.end()) {
// key doesn't exist.
return -1;
}
// key exists.
Node *node = iter->second;
removeNode(node);
addAtHead(node);
return node->val;
}
void put(int key, int value) {
auto iter = keyToNode.find(key);
if (iter == keyToNode.end()) {
// key doesn't exist.
if (len < cap) {
Node *newNode = new Node(key, value);
addAtHead(newNode);
return;
}
// len >= cap is true.
Node *node = head->prev;
removeNode(node);
node->key = key;
node->val = value;
addAtHead(node);
return;
}
// key exists.
Node *node = iter->second;
removeNode(node);
node->val = value;
addAtHead(node);
return;
}
private:
int cap;
int len;
Node *head;
unordered_map<int, Node*> keyToNode;
void removeNode(Node *node) {
node->prev->next = node->next;
node->next->prev = node->prev;
node->next = node;
node->prev = node;
keyToNode.erase(node->key);
--len;
}
void addAtHead(Node *node) {
node->next = head->next;
node->prev = head;
head->next->prev = node;
head->next = node;
keyToNode[node->key] = node;
++len;
}
};
/**
* 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);
*/
```
## Time Complexity
* `LRUCache`
$O(1)$
* `get`
$O(1)$
* `put`
$O(1)$
## Space Complexity
* `LRUCache`
$O(1)$
* `get`
$O(1)$
* `put`
$O(1)$
# Miscellaneous
<!--
# Test Cases
```
["LRUCache","put","put","get","put","get","put","get","get","get"]
[[2],[1,1],[2,2],[1],[3,3],[2],[4,4],[1],[3],[4]]
```
```
["LRUCache","put","get","put","get","get"]
[[1],[2,1],[2],[3,2],[2],[3]]
```
```
["LRUCache","get","put","get","put","put","get","get"]
[[2],[2],[2,6],[1],[1,5],[1,2],[1],[2]]
```
```
["LRUCache","put","put","put","put","get","get"]
[[2],[2,1],[1,1],[2,3],[4,1],[1],[2]]
```
```
["LRUCache","get","get","put","get","put","put","put","put","get","put"]
[[1],[6],[8],[12,1],[2],[15,11],[5,2],[1,15],[4,2],[5],[15,15]]
```
* Wrong Answer:
```
["LRUCache","put","put","put","put","put","get","put","get","get","put","get","put","put","put","get","put","get","get","get","get","put","put","get","get","get","put","put","get","put","get","put","get","get","get","put","put","put","get","put","get","get","put","put","get","put","put","put","put","get","put","put","get","put","put","get","put","put","put","put","put","get","put","put","get","put","get","get","get","put","get","get","put","put","put","put","get","put","put","put","put","get","get","get","put","put","put","get","put","put","put","get","put","put","put","get","get","get","put","put","put","put","get","put","put","put","put","put","put","put"]
[[10],[10,13],[3,17],[6,11],[10,5],[9,10],[13],[2,19],[2],[3],[5,25],[8],[9,22],[5,5],[1,30],[11],[9,12],[7],[5],[8],[9],[4,30],[9,3],[9],[10],[10],[6,14],[3,1],[3],[10,11],[8],[2,14],[1],[5],[4],[11,4],[12,24],[5,18],[13],[7,23],[8],[12],[3,27],[2,12],[5],[2,9],[13,4],[8,18],[1,7],[6],[9,29],[8,21],[5],[6,30],[1,12],[10],[4,15],[7,22],[11,26],[8,17],[9,29],[5],[3,4],[11,30],[12],[4,29],[3],[9],[6],[3,4],[1],[10],[3,29],[10,28],[1,20],[11,13],[3],[3,12],[3,8],[10,9],[3,26],[8],[7],[5],[13,17],[2,27],[11,15],[12],[9,19],[2,15],[3,16],[1],[12,17],[9,1],[6,19],[4],[5],[5],[8,1],[11,7],[5,2],[9,28],[1],[2,2],[7,4],[4,22],[7,24],[9,26],[13,28],[11,26]]
```
* TLE
https://leetcode.com/problems/lru-cache/submissions/855829391/
-->