--- 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/ -->