都要用个哈希表将查找值=映射到=>存储位置,而存储位置=也要能映射回=>查找值。
O(1)时间插入删除
无重复值:值=>值在数组的idx;有重复值:值=>值在数组的idx集合。在数组末增减元素。
O(1)时间增减频率值
class AllOne {
// 映射表table按值分行
struct ValueRow { int value; unordered_set<string> keys; };
list<ValueRow> table;
unordered_map<string, list<ValueRow>::iterator> rowPtrs;
private:
void deleteKey(const string &key, list<ValueRow>::iterator &row) {
row->keys.erase(key);
if (row->keys.empty()) table.erase(row);
rowPtrs.erase(key);
}
void insertKey(const string &key, list<ValueRow>::iterator &row) {
row->keys.insert(key);
rowPtrs[key] = row;
}
void moveKey(const string &key, list<ValueRow>::iterator &from, list<ValueRow>::iterator &to) {
deleteKey(key, from);
insertKey(key, to);
}
public:
/** Initialize your data structure here. */
AllOne() {
}
/** Inserts a new key <Key> with value 1. Or increments an existing key by 1. */
void inc(string key) {
if (!rowPtrs.count(key)) { // 先插入0,待会儿和其他情况一起增1
rowPtrs[key] = table.insert(table.begin(), {0, { key }});
}
auto currRow = rowPtrs[key], nextRow = next(currRow);
int nextValueNeeded = currRow->value + 1;
if (nextRow == table.end() || nextRow->value != nextValueNeeded) { // 插入新行
nextRow = table.insert(nextRow, {nextValueNeeded, { }});
}
moveKey(key, currRow, nextRow);
}
/** Decrements an existing key by 1. If Key's value is 1, remove it from the data structure. */
void dec(string key) {
if (!rowPtrs.count(key)) return;
auto currRow = rowPtrs[key];
if (currRow->value == 1) {
deleteKey(key, currRow);
return;
}
auto prevRow = prev(currRow);
int prevValueNeeded = currRow->value - 1;
if (currRow == table.begin() || prevRow->value != prevValueNeeded) {
prevRow = table.insert(currRow, {prevValueNeeded, { }});
}
moveKey(key, currRow, prevRow);
}
/** Returns one of the keys with maximal value. */
string getMaxKey() {
return table.empty() ? "" : *table.rbegin()->keys.begin();
}
/** Returns one of the keys with Minimal value. */
string getMinKey() {
return table.empty() ? "" : *table.begin()->keys.begin();
}
};
LRU cache
比按频率分行的情况简单,只需1维链表。
class LRUCache{
// 把entry{key,value}用链表串起来,
// 每次访问把entry移到表头,删除lru时删除表尾
struct Entry { int key; int value; };
list<Entry> l; // 实际存储
unordered_map<int, list<Entry>::iterator> entryPtrs; // key=>entry
int capacity;
private:
void touch(int key) {
// toList.splice(toListIterator, fromList, fromListSingleIterator)
l.splice(l.begin(), l, entryPtrs[key]);
entryPtrs[key] = l.begin();
}
public:
LRUCache(int capacity) {
this->capacity = capacity;
}
int get(int key) {
if (!entryPtrs.count(key)) return -1;
touch(key);
return entryPtrs[key]->value;
}
void put(int key, int value) {
if (capacity == 0) return;
if (!entryPtrs.count(key)) {
if (l.size() == capacity) { // 删除表尾
entryPtrs.erase(l.back().key);
l.pop_back();
}
l.push_front({key, value});
entryPtrs[key] = l.begin();
} else {
entryPtrs[key]->value = value;
touch(key);
}
}
};
LFU Cache
class LFUCache {
// 映射表table按频率分行,每行行首放最近使用项
struct Entry { int key; int value; };
struct FreqRow { int freq; list<Entry> entries; };
list<FreqRow> table;
struct EntryPtr { list<FreqRow>::iterator row; list<Entry>::iterator entry; };
unordered_map<int, EntryPtr> entryPtrs;
int capacity;
private:
void moveKey(int key, list<FreqRow>::iterator &to) {
auto from = entryPtrs[key].row;
to->entries.splice(to->entries.begin(), from->entries, entryPtrs[key].entry);
if (from->entries.empty()) table.erase(from);
entryPtrs[key] = { to, to->entries.begin() };
}
// 将entry从原行删除、插入"freq+1"行
void incFreq(int key) {
auto currRow = entryPtrs[key].row, nextRow = next(currRow);
int nextFreq = currRow->freq + 1;
if (nextRow == table.end() || nextRow->freq != nextFreq) { // 插入新行
nextRow = table.insert(nextRow, { nextFreq, { }});
}
moveKey(key, nextRow);
}
// 删除最小频率lfu的行中最少最近使用lru项
void evict() {
if (table.empty()) return;
auto lfu = table.begin();
entryPtrs.erase(lfu->entries.back().key);
lfu->entries.pop_back();
if (lfu->entries.empty()) table.erase(lfu);
}
public:
LFUCache(int capacity) {
this->capacity = capacity;
}
int get(int key) {
if (!entryPtrs.count(key)) return -1;
incFreq(key);
return entryPtrs[key].entry->value;
}
void put(int key, int value) {
if (capacity == 0) return;
if (!entryPtrs.count(key)) {
if (entryPtrs.size() == capacity) evict();
// 先插入freq=0的行,待会儿和其他情况一起增1
auto row = table.insert(table.begin(), { 0, {{key, value}} });
entryPtrs[key] = { row, row->entries.begin() };
} else {
entryPtrs[key].entry->value = value;
}
incFreq(key);
}
};