From d798871fbc9eb86ff19a2a963bf5a940fac7abca Mon Sep 17 00:00:00 2001 From: Prad Nukala Date: Tue, 1 Sep 2026 13:31:31 -0400 Subject: [PATCH] docs(docs): add LRU Cache problem documentation --- .../content/(hash-table)/146-lru-cache.mdx | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 apps/docs/content/(hash-table)/146-lru-cache.mdx diff --git a/apps/docs/content/(hash-table)/146-lru-cache.mdx b/apps/docs/content/(hash-table)/146-lru-cache.mdx new file mode 100644 index 0000000..2bca646 --- /dev/null +++ b/apps/docs/content/(hash-table)/146-lru-cache.mdx @@ -0,0 +1,85 @@ +--- +title: '146. LRU Cache' +description: Design a data structure that follows the constraints of a Least Recently Used (LRU) cache +sidebar: + label: 'LRU Cache' + badge: 'Medium' +--- + +Hybrid Structures + +### Example 1: +- Input: `` +- Output: `` +- Explanation: Input ["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"] `[[2]`, [1, 1], [2, 2], `[1]`, [3, 3], `[2]`, [4, 4], `[1]`, `[3]`, [4]] Output [null, null, null, `1`, null, `-1`, null, `-1`, `3`, 4] Explanation LRUCache lRUCache = new LRUCache(2); lRUCache.put(1, `1`); // cache is {1=1} lRUCache.put(2, `2`); // cache is {1=1, 2=2} lRUCache.get(1); // return `1` lRUCache.put(3, `3`); // LRU `key` was `2`, evicts `key 2`, cache is {1=1, 3=3} lRUCache.get(2); // returns `-1` (not found) lRUCache.put(4, `4`); // LRU `key` was `1`, evicts `key 1`, cache is {4=4, 3=3} lRUCache.get(1); // return `-1` (not found) lRUCache.get(3); // return `3` lRUCache.get(4); // return `4` + +### Constraints: + +- `1 <= capacity <= 3000` +- `0 <= key <= 10^4` +- `0 <= value <= 10^5` +- At most 2 * 10^5 calls will be made to get and put. + +## Solution + +```py +class Node: + def __init__(self, key=0, value=0): + self.key = key + self.value = value + self.prev = None + self.next = None + + +class LRUCache: + def __init__(self, capacity: int): + self.capacity = capacity + self.cache = {} + self.head = Node() + self.tail = Node() + self.head.next = self.tail # pyright: ignore[reportAttributeAccessIssue] + self.tail.prev = self.head # pyright: ignore[reportAttributeAccessIssue] + + def _remove_node(self, node): + prev_node = node.prev + next_node = node.next + prev_node.next = next_node + next_node.prev = prev_node + + def _add_node(self, node): + node.prev = self.head + node.next = self.head.next + self.head.next.prev = node # pyright: ignore[reportAttributeAccessIssue] + self.head.next = node + + def get(self, key: int) -> int: + if key not in self.cache: + return -1 + + node = self.cache[key] + self._remove_node(node) + self._add_node(node) + return node.value + + def put(self, key: int, value: int) -> None: + if key in self.cache: + node = self.cache[key] + node.value = value + self._remove_node(node) + self._add_node(node) + else: + new_node = Node(key, value) + self.cache[key] = new_node + self._add_node(new_node) + + if len(self.cache) > self.capacity: + lru = self.tail.prev + self._remove_node(lru) + del self.cache[lru.key] # pyright: ignore[reportAttributeAccessIssue] + + +# Your LRUCache object will be instantiated and called as such: +# obj = LRUCache(capacity) +# param_1 = obj.get(key) +# obj.put(key,value) +```