146. LRU Cache
Design a data structure that follows the constraints of a Least Recently Used (LRU) cache
Hash TableExample 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); // return1lRUCache.put(3,3); // LRUkeywas2, evictskey 2, cache is {1=1, 3=3} lRUCache.get(2); // returns-1(not found) lRUCache.put(4,4); // LRUkeywas1, evictskey 1, cache is {4=4, 3=3} lRUCache.get(1); // return-1(not found) lRUCache.get(3); // return3lRUCache.get(4); // return4
Constraints:
1 <= capacity <= 30000 <= key <= 10^40 <= value <= 10^5- At most 2 * 10^5 calls will be made to get and put.
Approach
Solution
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):
# Insert just before the tail (most recent at end)
node.next = self.tail
node.prev = self.tail.prev
self.tail.prev.next = node # pyright: ignore[reportAttributeAccessIssue]
self.tail.prev = 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.head.next # Oldest node is next to the head
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)