0%

460. LFU 缓存

460. LFU 缓存

自己维护一个双向链表

记录每个count的值的最后一位是哪个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
class LFUCache {
public:
LFUCache(int capacity) : head(new Node(-1, 0, -1)), tail(new Node(-1, 0, INT_MAX)), size(0), capacity(capacity) {
head->next = tail;
tail->prev = head;
}

int get(int key) {
if(capacity == 0)
return -1;
if(!map.count(key))
return -1;
auto ret = map[key]->value;
int oldc = map[key]->count++;
if(oldc != map[key]->prev->count && oldc != map[key]->next->count)
location.erase(oldc);
else if(oldc == map[key]->prev->count && oldc != map[key]->next->count)
location[oldc] = map[key]->prev;
int c = oldc + 1;
if(c >= map[key]->next->count)
moveToNext(location[map[key]->next->count], map[key]);
if(c == map[key]->next->count)
moveToNext(location[c], map[key]);
location[c] = map[key];
return ret;
}

void put(int key, int value) {
if(capacity == 0)
return;
if(!map.count(key))
{
if(++size > capacity)
{
--size;
removeHead();
}
addToHead(key, value);
}else
{
map[key]->value = value;
int oldc = map[key]->count++;
if(oldc != map[key]->prev->count && oldc != map[key]->next->count)
location.erase(oldc);
else if(oldc == map[key]->prev->count && oldc != map[key]->next->count)
location[oldc] = map[key]->prev;
}
auto c = map[key]->count;
if(c >= map[key]->next->count)
moveToNext(location[map[key]->next->count], map[key]);
if(c == map[key]->next->count)
moveToNext(location[c], map[key]);
location[c] = map[key];
}
private:
struct Node
{
int key;
int count;
int value;
Node* prev;
Node* next;
Node(int key, int value, int count = 1) : key(key), value(value), count(count) {}
};
Node *head, *tail;
int size, capacity;
unordered_map<int, Node*> map;
unordered_map<int, Node*> location;
private:
void exchangeNearbyNodes(Node* n1, Node* n2)
{
n1->next = n2->next;
n2->next->prev = n1;
n2->next = n1;
n2->prev = n1->prev;
n1->prev->next = n2;
n1->prev = n2;
}
void removeHead()
{
if(head->next == tail)
return;
auto node = head->next;
head->next->next->prev = head;
head->next = head->next->next;
map.erase(node->key);
if(node->next->count != node->count)
location.erase(node->count);
delete node;
}
void addToHead(int key, int value)
{
auto node = new Node(key, value);
node->next = head->next;
head->next->prev = node;
head->next = node;
node->prev = head;
map.emplace(key, node);
}
void isolatedNode(Node* node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
}
void moveToNext(Node* prev, Node* node)
{
isolatedNode(node);
node->next = prev->next;
node->prev = prev;
prev->next->prev = node;
prev->next = node;
}
};

/**
* Your LFUCache object will be instantiated and called as such:
* LFUCache* obj = new LFUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/

get: O(1)

put: O(1)

使用红黑树(c++中的set)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class LFUCache {
public:
LFUCache(int capacity) : time(0), capacity(capacity) {

}

int get(int key) {
if(capacity == 0)
return -1;
if(!map.count(key))
return -1;
set.erase(map[key]);
map[key].time = ++time;
++map[key].count;
set.insert(map[key]);
return map[key].value;
}

void put(int key, int value) {
if(capacity == 0)
return;
if(map.count(key))
{
set.erase(map[key]);
map[key].time = ++time;
++map[key].count;
map[key].value = value;
set.insert(map[key]);
}else
{
if(map.size() == capacity)
{
auto node = set.begin();
map.erase(node->key);
set.erase(node);
}
Node node{key, value, 1, ++time};
map.emplace(key, node);
set.insert(std::move(node));
}
}
private:
struct Node
{
int key;
int value;
int count;
int time;
Node() = default;
Node(int key, int value, int count, int time) : key(key), value(value), count(count), time(time) {}
bool operator < (const Node& rhs) const
{
return count == rhs.count ? time < rhs.time : count < rhs.count;
}
};
int time;
unordered_map<int, Node> map;
set<Node> set;
int capacity;
};

/**
* Your LFUCache object will be instantiated and called as such:
* LFUCache* obj = new LFUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/

get: O(logn)

put: O(logn)

使用双哈希表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
class LFUCache {
public:
LFUCache(int capacity) : capacity(capacity), minFreq(1) {

}

int get(int key) {
if(capacity == 0)
return -1;
if(!map.count(key))
return -1;
auto it = map[key];
auto count = it->count;
auto value = it->value;
freq[count].erase(it);
if(freq[count].size() == 0)
{
freq.erase(count);
if(count == minFreq)
++minFreq;
}
++count;
freq[count].push_front(Node(key, value, count));
map[key] = freq[count].begin();
return value;
}

void put(int key, int value) {
if(capacity == 0)
return;
if(!map.count(key))
{
if(map.size() == capacity)
{
auto it = --freq[minFreq].end(); // 不是随机迭代器,不能用-1
map.erase(it->key);
freq[minFreq].pop_back();
if(freq[minFreq].size() == 0)
freq.erase(minFreq);
}
freq[1].push_front(Node(key, value, 1));
map.emplace(key, freq[1].begin());
minFreq = 1;
}else
{
auto it = map[key];
auto count = it->count;
freq[count].erase(it);
if(freq[count].size() == 0)
{
freq.erase(count);
if(count == minFreq)
++minFreq;
}
++count;
freq[count].push_front(Node(key, value, count));
map[key] = freq[count].begin();
}
}
private:
struct Node
{
int key;
int value;
int count;
Node(int key, int value, int count) : key(key), value(value), count(count) {}
};
unordered_map<int, list<Node>::iterator> map;
unordered_map<int, list<Node>> freq;
int capacity;
int minFreq;
};

/**
* Your LFUCache object will be instantiated and called as such:
* LFUCache* obj = new LFUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/