Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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

‎README.md‎

Lines changed: 1 addition & 0 deletions
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)

‎README_EN.md‎

Lines changed: 1 addition & 0 deletions
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)

‎solution/0100-0199/0146.Lru Cache/README.md‎

Lines changed: 186 additions & 1 deletion
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)

AltStyle によって変換されたページ (->オリジナル) /