---
# System prepended metadata

title: '[146. LRU Cache](https://leetcode.com/problems/lru-cache/)'
tags: [leetcode]

---

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