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 4240dff

Browse files
feat: add solutions to lc problem: No.0460 (doocs#1675)
No.0460.LFU Cache
1 parent 8d2ba7f commit 4240dff

File tree

4 files changed

+655
-9
lines changed

4 files changed

+655
-9
lines changed

‎solution/0400-0499/0460.LFU Cache/README.md‎

Lines changed: 232 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,28 @@ lfu.get(4); // 返回 4
6969

7070
<!-- 这里可写通用的实现逻辑 -->
7171

72-
[LRU 缓存](/solution/0100-0199/0146.Lru%20Cache/README.md) 类似的思路,用 `map<key, node>``map<freq, list<node>>` 存储不同使用频率的节点
72+
**方法一:双哈希表 + 双向链表**
7373

74-
对于 `get` 操作,判断 key 是否存在哈希表中:
74+
我们定义两个哈希表,其中:
7575

76-
- 若不存在,返回 -1
77-
- 若存在,增加节点的使用频率,返回节点值
76+
- 哈希表 $map$:用于存储缓存的键值对,哈希表的键 $key$ 对应到缓存节点 $node,ドル方便 $O(1)$ 时间内获取缓存节点。
77+
- 哈希表 $freqMap$:用于存储使用频率相同的缓存节点的双向链表,哈希表的键 $freq$ 对应到双向链表 $list,ドル方便 $O(1)$ 时间内获取使用频率相同的缓存节点的双向链表。
7878

79-
对于 `put` 操作,同样判断 key 是否存在哈希表中:
79+
另外,我们还需要维护一个变量 $minFreq,ドル用于记录当前最小的使用频率,方便 $O(1)$ 时间内获取最小使用频率的缓存节点。
8080

81-
- 若不存在,首先判断缓存容量是否足够,不够的话需要先删除使用次数最少的节点。然后再创建新节点,插入使用频率为 1 的双链表
82-
- 若存在,修改原节点的值,增加节点的使用频率
81+
对于 $get(key)$ 操作:
82+
83+
我们首先判断 $capacity$ 是否为 0ドル$ 或者 $map$ 中是否存在键 $key,ドル如果不存在则返回 $-1$;否则从 $map$ 中获取缓存节点 $node,ドル并将 $node$ 的使用频率加 1ドル,ドル最后返回 $node$ 的值。
84+
85+
对于 $put(key, value)$ 操作:
86+
87+
我们首先判断 $capacity$ 是否为 0ドル,ドル如果为 0ドル$ 则直接返回;
88+
89+
否则判断 $map$ 中是否存在键 $key,ドル如果存在则从 $map$ 中获取缓存节点 $node,ドル更新 $node$ 的值为 $value,ドル并将 $node$ 的使用频率加 1ドル,ドル最后返回 $node$ 的值;
90+
91+
如果不存在则判断 $map$ 的长度是否等于 $capacity,ドル如果等于 $capacity$ 则从 $freqMap$ 中获取使用频率最小的双向链表 $list,ドル从 $list$ 中删除最后一个节点,并且移除该节点对应的键值对。然后创建新的缓存节点 $node,ドル将 $node$ 的使用频率设置为 1ドル,ドル将 $node$ 添加到 $map$ 和 $freqMap$ 中,最后将 $minFreq$ 设置为 1ドル$。
92+
93+
时间复杂度方面,操作 $get$ 和 $put$ 的时间复杂度都是 $O(1)$。空间复杂度 $O(n),ドル其中 $n$ 为缓存的容量。
8394

8495
<!-- tabs:start -->
8596

@@ -88,7 +99,94 @@ lfu.get(4); // 返回 4
8899
<!-- 这里可写当前语言的特殊实现逻辑 -->
89100

90101
```python
91-
102+
class Node:
103+
def __init__(self, key: int, value: int) -> None:
104+
self.key = key
105+
self.value = value
106+
self.freq = 1
107+
self.prev = None
108+
self.next = None
109+
110+
111+
class DoublyLinkedList:
112+
def __init__(self) -> None:
113+
self.head = Node(-1, -1)
114+
self.tail = Node(-1, -1)
115+
self.head.next = self.tail
116+
self.tail.prev = self.head
117+
118+
def add_first(self, node: Node) -> None:
119+
node.prev = self.head
120+
node.next = self.head.next
121+
self.head.next.prev = node
122+
self.head.next = node
123+
124+
def remove(self, node: Node) -> Node:
125+
node.next.prev = node.prev
126+
node.prev.next = node.next
127+
node.next, node.prev = None, None
128+
return node
129+
130+
def remove_last(self) -> Node:
131+
return self.remove(self.tail.prev)
132+
133+
def is_empty(self) -> bool:
134+
return self.head.next == self.tail
135+
136+
137+
class LFUCache:
138+
def __init__(self, capacity: int):
139+
self.capacity = capacity
140+
self.min_freq = 0
141+
self.map = defaultdict(Node)
142+
self.freq_map = defaultdict(DoublyLinkedList)
143+
144+
def get(self, key: int) -> int:
145+
if self.capacity == 0 or key not in self.map:
146+
return -1
147+
node = self.map[key]
148+
self.incr_freq(node)
149+
return node.value
150+
151+
def put(self, key: int, value: int) -> None:
152+
if self.capacity == 0:
153+
return
154+
if key in self.map:
155+
node = self.map[key]
156+
node.value = value
157+
self.incr_freq(node)
158+
return
159+
if len(self.map) == self.capacity:
160+
ls = self.freq_map[self.min_freq]
161+
node = ls.remove_last()
162+
self.map.pop(node.key)
163+
node = Node(key, value)
164+
self.add_node(node)
165+
self.map[key] = node
166+
self.min_freq = 1
167+
168+
def incr_freq(self, node: Node) -> None:
169+
freq = node.freq
170+
ls = self.freq_map[freq]
171+
ls.remove(node)
172+
if ls.is_empty():
173+
self.freq_map.pop(freq)
174+
if freq == self.min_freq:
175+
self.min_freq += 1
176+
node.freq += 1
177+
self.add_node(node)
178+
179+
def add_node(self, node: Node) -> None:
180+
freq = node.freq
181+
ls = self.freq_map[freq]
182+
ls.add_first(node)
183+
self.freq_map[freq] = ls
184+
185+
186+
# Your LFUCache object will be instantiated and called as such:
187+
# obj = LFUCache(capacity)
188+
# param_1 = obj.get(key)
189+
# obj.put(key,value)
92190
```
93191

94192
### **Java**
@@ -214,6 +312,132 @@ class LFUCache {
214312
}
215313
```
216314

315+
### **C++**
316+
317+
```cpp
318+
class Node {
319+
public:
320+
int key;
321+
int value;
322+
int freq;
323+
Node* prev;
324+
Node* next;
325+
Node(int key, int value) {
326+
this->key = key;
327+
this->value = value;
328+
this->freq = 1;
329+
this->prev = nullptr;
330+
this->next = nullptr;
331+
}
332+
};
333+
334+
class DoublyLinkedList {
335+
public:
336+
Node* head;
337+
Node* tail;
338+
DoublyLinkedList() {
339+
this->head = new Node(-1, -1);
340+
this->tail = new Node(-1, -1);
341+
this->head->next = this->tail;
342+
this->tail->prev = this->head;
343+
}
344+
void addFirst(Node* node) {
345+
node->prev = this->head;
346+
node->next = this->head->next;
347+
this->head->next->prev = node;
348+
this->head->next = node;
349+
}
350+
Node* remove(Node* node) {
351+
node->next->prev = node->prev;
352+
node->prev->next = node->next;
353+
node->next = nullptr;
354+
node->prev = nullptr;
355+
return node;
356+
}
357+
Node* removeLast() {
358+
return remove(this->tail->prev);
359+
}
360+
bool isEmpty() {
361+
return this->head->next == this->tail;
362+
}
363+
};
364+
365+
class LFUCache {
366+
public:
367+
LFUCache(int capacity) {
368+
this->capacity = capacity;
369+
this->minFreq = 0;
370+
}
371+
372+
int get(int key) {
373+
if (capacity == 0 || map.find(key) == map.end()) {
374+
return -1;
375+
}
376+
Node* node = map[key];
377+
incrFreq(node);
378+
return node->value;
379+
}
380+
381+
void put(int key, int value) {
382+
if (capacity == 0) {
383+
return;
384+
}
385+
if (map.find(key) != map.end()) {
386+
Node* node = map[key];
387+
node->value = value;
388+
incrFreq(node);
389+
return;
390+
}
391+
if (map.size() == capacity) {
392+
DoublyLinkedList* list = freqMap[minFreq];
393+
Node* node = list->removeLast();
394+
map.erase(node->key);
395+
}
396+
Node* node = new Node(key, value);
397+
addNode(node);
398+
map[key] = node;
399+
minFreq = 1;
400+
}
401+
402+
private:
403+
int capacity;
404+
int minFreq;
405+
unordered_map<int, Node*> map;
406+
unordered_map<int, DoublyLinkedList*> freqMap;
407+
408+
void incrFreq(Node* node) {
409+
int freq = node->freq;
410+
DoublyLinkedList* list = freqMap[freq];
411+
list->remove(node);
412+
if (list->isEmpty()) {
413+
freqMap.erase(freq);
414+
if (freq == minFreq) {
415+
minFreq++;
416+
}
417+
}
418+
node->freq++;
419+
addNode(node);
420+
}
421+
422+
void addNode(Node* node) {
423+
int freq = node->freq;
424+
if (freqMap.find(freq) == freqMap.end()) {
425+
freqMap[freq] = new DoublyLinkedList();
426+
}
427+
DoublyLinkedList* list = freqMap[freq];
428+
list->addFirst(node);
429+
freqMap[freq] = list;
430+
}
431+
};
432+
433+
/**
434+
* Your LFUCache object will be instantiated and called as such:
435+
* LFUCache* obj = new LFUCache(capacity);
436+
* int param_1 = obj->get(key);
437+
* obj->put(key,value);
438+
*/
439+
```
440+
217441
### **Go**
218442
219443
```go

0 commit comments

Comments
(0)

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