Skip to content

Commit 8da5ac6

Browse files
committed
feat: update solutions to leetcode problem: No.0146. LRU Cache
1 parent 5a027d1 commit 8da5ac6

File tree

6 files changed

+469
-71
lines changed

6 files changed

+469
-71
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@
173173

174174
### 设计
175175

176+
- [LRU 缓存机制](/solution/0100-0199/0146.Lru%20Cache/README.md)
176177
- [实现 Trie (前缀树)](/solution/0200-0299/0208.Implement%20Trie%20%28Prefix%20Tree%29/README.md)
177178
- [实现 Trie (前缀树) II](/solution/1800-1899/1804.Implement%20Trie%20II%20%28Prefix%20Tree%29/README.md)
178179
- [设计哈希集合](/solution/0700-0799/0705.Design%20HashSet/README.md)

Diff for: README_EN.md

+1
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ Complete solutions to [LeetCode](https://leetcode-cn.com/problemset/all/), [LCOF
166166

167167
### Design
168168

169+
- [LRU Cache](/solution/0100-0199/0146.Lru%20Cache/README_EN.md)
169170
- [Implement Trie (Prefix Tree)](<solution/0200-0299/0208.Implement%20Trie%20(Prefix%20Tree)/README_EN.md>)
170171
- [Implement Trie II (Prefix Tree)](/solution/1800-1899/1804.Implement%20Trie%20II%20%28Prefix%20Tree%29/README_EN.md)
171172
- [Design HashSet](/solution/0700-0799/0705.Design%20HashSet/README_EN.md)

Diff for: solution/0100-0199/0146.Lru Cache/README.md

+186-1
Original file line numberDiff line numberDiff line change
@@ -59,27 +59,212 @@ lRUCache.get(4); // 返回 4
5959
<li>最多调用 <code>3 * 10<sup>4</sup></code> 次 <code>get</code> 和 <code>put</code></li>
6060
</ul>
6161

62-
6362
## 解法
6463

6564
<!-- 这里可写通用的实现逻辑 -->
6665

66+
“哈希表 + 双向链表”实现。其中:
67+
68+
- 双向链表按照被使用的顺序存储 kv 键值对,靠近头部的 kv 键值对是最近使用的,而靠近尾部的键值对是最久未使用的。
69+
- 哈希表通过缓存的 key 映射到双向链表中的位置。我们可以在 `O(1)` 时间内定位到缓存的 key 所对应的 value 在链表中的位置。
70+
71+
对于 `get` 操作,判断 key 是否存在哈希表中:
72+
73+
- 若不存在,返回 -1
74+
- 若存在,则 key 对应的节点 node 是最近使用的节点。将该节点移动到双向链表的头部,最后返回该节点的值即可。
75+
76+
对于 `put` 操作,同样先判断 key 是否存在哈希表中:
77+
78+
- 若不存在,则创建一个新的 node 节点,放入哈希表中。然后在双向链表的头部添加该节点。接着判断双向链表节点数是否超过 capacity。若超过,则删除双向链表的尾部节点,以及在哈希表中对应的项。
79+
- 若存在,则更新 node 节点的值,然后该节点移动到双向链表的头部。
80+
81+
双向链表节点(哈希表的 value)的结构如下:
82+
83+
```java
84+
class Node {
85+
int key;
86+
int value;
87+
Node prev;
88+
Node next;
89+
Node() {
90+
91+
}
92+
Node(int key, int value) {
93+
this.key = key;
94+
this.value = value;
95+
}
96+
}
97+
```
98+
99+
你可能会问,哈希表的 value 为何还要存放 key?
100+
101+
这是因为,双向链表有一个删除尾节点的操作。我们定位到双向链表的尾节点,在链表中删除之后,还要找到该尾节点在哈希表中的位置,因此需要根据 value 中存放的 key,定位到哈希表的数据项,然后将其删除。
102+
67103
<!-- tabs:start -->
68104

69105
### **Python3**
70106

71107
<!-- 这里可写当前语言的特殊实现逻辑 -->
72108

73109
```python
110+
class Node:
111+
def __init__(self, key=0, value=0):
112+
self.key = key
113+
self.value = value
114+
self.prev = None
115+
self.next = None
116+
117+
class LRUCache:
118+
119+
def __init__(self, capacity: int):
120+
self.size = 0
121+
self.capacity = capacity
122+
self.cache = {}
123+
self.head = Node()
124+
self.tail = Node()
125+
self.head.next = self.tail
126+
self.tail.prev = self.head
74127

128+
def get(self, key: int) -> int:
129+
if key not in self.cache:
130+
return -1
131+
node = self.cache[key]
132+
self._move_to_head(node)
133+
return node.value
134+
135+
def put(self, key: int, value: int) -> None:
136+
if key not in self.cache:
137+
new_node = Node(key, value)
138+
self.cache[key] = new_node
139+
self._add_to_head(new_node)
140+
self.size += 1
141+
if self.size > self.capacity:
142+
node = self._remove_tail()
143+
self.cache.pop(node.key)
144+
self.size -= 1
145+
else:
146+
node = self.cache[key]
147+
node.value = value
148+
self._move_to_head(node)
149+
150+
def _move_to_head(self, node):
151+
self._remove_node(node)
152+
self._add_to_head(node)
153+
154+
def _remove_node(self, node):
155+
node.prev.next = node.next
156+
node.next.prev = node.prev
157+
158+
def _add_to_head(self, node):
159+
node.next = self.head.next
160+
node.next.prev = node
161+
node.prev = self.head
162+
self.head.next = node
163+
164+
def _remove_tail(self):
165+
node = self.tail.prev
166+
self._remove_node(node)
167+
return node
168+
169+
# Your LRUCache object will be instantiated and called as such:
170+
# obj = LRUCache(capacity)
171+
# param_1 = obj.get(key)
172+
# obj.put(key,value)
75173
```
76174

77175
### **Java**
78176

79177
<!-- 这里可写当前语言的特殊实现逻辑 -->
80178

81179
```java
180+
class LRUCache {
181+
class Node {
182+
int key;
183+
int value;
184+
Node prev;
185+
Node next;
186+
Node() {
187+
188+
}
189+
Node(int key, int value) {
190+
this.key = key;
191+
this.value = value;
192+
}
193+
}
194+
195+
private int size;
196+
private int capacity;
197+
private Map<Integer, Node> cache;
198+
private Node head;
199+
private Node tail;
200+
201+
public LRUCache(int capacity) {
202+
this.size = 0;
203+
this.capacity = capacity;
204+
cache = new HashMap<>();
205+
head = new Node();
206+
tail = new Node();
207+
head.next = tail;
208+
tail.prev = head;
209+
}
210+
211+
public int get(int key) {
212+
Node node = cache.get(key);
213+
if (node == null) {
214+
return -1;
215+
}
216+
moveToHead(node);
217+
return node.value;
218+
}
219+
220+
public void put(int key, int value) {
221+
Node node = cache.get(key);
222+
if (node == null) {
223+
Node newNode = new Node(key, value);
224+
cache.put(key, newNode);
225+
addToHead(newNode);
226+
++size;
227+
if (size > capacity) {
228+
Node tail = removeTail();
229+
cache.remove(tail.key);
230+
--size;
231+
}
232+
} else {
233+
node.value = value;
234+
moveToHead(node);
235+
}
236+
}
237+
238+
private void moveToHead(Node node) {
239+
removeNode(node);
240+
addToHead(node);
241+
}
242+
243+
private void removeNode(Node node) {
244+
node.prev.next = node.next;
245+
node.next.prev = node.prev;
246+
}
247+
248+
private void addToHead(Node node) {
249+
node.next = head.next;
250+
head.next = node;
251+
node.next.prev = node;
252+
node.prev = head;
253+
}
254+
255+
private Node removeTail() {
256+
Node node = tail.prev;
257+
removeNode(node);
258+
return node;
259+
}
260+
}
82261

262+
/**
263+
* Your LRUCache object will be instantiated and called as such:
264+
* LRUCache obj = new LRUCache(capacity);
265+
* int param_1 = obj.get(key);
266+
* obj.put(key,value);
267+
*/
83268
```
84269

85270
### **...**

0 commit comments

Comments
 (0)