|
1 | | -class Node: |
2 | | - __slots__ = ("key", "value", "prev", "next") |
3 | | - |
| 1 | +class DLLNode: |
4 | 2 | def __init__(self, key, value): |
5 | 3 | self.key = key |
6 | 4 | self.value = value |
7 | 5 | self.prev = None |
8 | 6 | self.next = None |
9 | 7 |
|
10 | 8 |
|
11 | | -class LruCache: |
12 | | - def __init__(self, limit: int): |
13 | | - if limit < 1: |
14 | | - raise ValueError(f"limit must be at least 1, got {limit}") |
| 9 | +class DoublyLinkedList: |
| 10 | + def __init__(self): |
| 11 | + self.head = DLLNode(None, None) |
| 12 | + self.tail = DLLNode(None, None) |
| 13 | + self.head.next = self.tail |
| 14 | + self.tail.prev = self.head |
15 | 15 |
|
16 | | - self._limit = limit |
17 | | - self.map: dict = {} |
18 | | - self.head = None |
19 | | - self.tail = None |
| 16 | + def add_to_front(self, node): |
| 17 | + node.next = self.head.next |
| 18 | + node.prev = self.head |
| 19 | + self.head.next.prev = node |
| 20 | + self.head.next = node |
20 | 21 |
|
21 | | - def _remove_node(self, node: Node): |
22 | | - """Remove a node from the linked list in O(1) time.""" |
23 | | - if node.prev: |
24 | | - node.prev.next = node.next |
25 | | - else: |
26 | | - self.head = node.next |
| 22 | + def remove(self, node): |
| 23 | + node.prev.next = node.next |
| 24 | + node.next.prev = node.prev |
27 | 25 |
|
28 | | - if node.next: |
29 | | - node.next.prev = node.prev |
30 | | - else: |
31 | | - self.tail = node.prev |
32 | | - |
33 | | - node.prev = None |
34 | | - node.next = None |
| 26 | + def move_to_front(self, node): |
| 27 | + self.remove(node) |
| 28 | + self.add_to_front(node) |
35 | 29 |
|
36 | | - def _add_node_to_head(self, node: Node): |
37 | | - """Add a node to the head of the linked list in O(1) time.""" |
38 | | - node.next = self.head |
39 | | - node.prev = None |
| 30 | + def remove_last(self): |
| 31 | + if self.tail.prev is self.head: |
| 32 | + return None |
| 33 | + last = self.tail.prev |
| 34 | + self.remove(last) |
| 35 | + return last |
40 | 36 |
|
41 | | - if self.head: |
42 | | - self.head.prev = node |
43 | | - else: |
44 | | - self.tail = node |
45 | | - |
46 | | - self.head = node |
| 37 | + |
| 38 | +class LruCache: |
| 39 | + def __init__(self, capacity: int): |
| 40 | + self.capacity = capacity |
| 41 | + self.cache = {} |
| 42 | + self.list = DoublyLinkedList() |
47 | 43 |
|
48 | 44 | def get(self, key): |
49 | | - """Return the value for key, Non if not present""" |
50 | | - node = self.map.get(key) |
51 | | - if node is None: |
52 | | - return None |
53 | | - |
54 | | - self._touch(node) |
| 45 | + if key not in self.cache: |
| 46 | + return -1 |
| 47 | + node = self.cache[key] |
| 48 | + self.list.move_to_front(node) |
55 | 49 | return node.value |
56 | 50 |
|
57 | | - def set(self, key, value) -> None: |
58 | | - """Combine value with key, evicting the LRU entry if necessary.""" |
59 | | - node = self.map.get(key) |
60 | | - |
61 | | - if node: |
| 51 | + def put(self, key, value): |
| 52 | + if key in self.cache: |
| 53 | + node = self.cache[key] |
62 | 54 | node.value = value |
63 | | - self._touch(node) |
64 | | - else: |
65 | | - if len(self.map) >= self._limit: |
66 | | - self._evict() |
67 | | - |
68 | | - new_node = Node(key, value) |
69 | | - self._add_node_to_head(new_node) |
70 | | - self.map[key] = new_node |
| 55 | + self.list.move_to_front(node) |
| 56 | + return |
71 | 57 |
|
72 | | - def _touch(self, node) -> None: |
73 | | - """Move an existing node to the head (most-recently-used position).""" |
74 | | - self._remove_node(node) |
75 | | - self._add_node_to_head(node) |
| 58 | + new_node = DLLNode(key, value) |
| 59 | + self.cache[key] = new_node |
| 60 | + self.list.add_to_front(new_node) |
76 | 61 |
|
77 | | - def _evict(self) -> None: |
78 | | - """Remove the least-recently-used entry (tail of the list).""" |
79 | | - if self.tail is None: |
80 | | - return |
81 | | - |
82 | | - lru = self.tail |
83 | | - self._remove_node(lru) |
84 | | - del self.map[lru.key] |
| 62 | + if len(self.cache) > self.capacity: |
| 63 | + last = self.list.remove_last() |
| 64 | + del self.cache[last.key] |
0 commit comments