LeetCode Solutions
460. LFU Cache
Time: $O(1)$ Space: $O(n)$
struct Node {
int key;
int value;
int freq;
list<int>::const_iterator it;
};
class LFUCache {
public:
LFUCache(int capacity) : capacity(capacity), minFreq(0) {}
int get(int key) {
if (!keyToNode.count(key))
return -1;
Node& node = keyToNode[key];
touch(node);
return node.value;
}
void put(int key, int value) {
if (capacity == 0)
return;
if (keyToNode.count(key)) {
Node& node = keyToNode[key];
node.value = value;
touch(node);
return;
}
if (keyToNode.size() == capacity) {
// Evict LRU key from the minFreq list
const int keyToEvict = freqToList[minFreq].back();
freqToList[minFreq].pop_back();
keyToNode.erase(keyToEvict);
}
minFreq = 1;
freqToList[1].push_front(key);
keyToNode[key] = {key, value, 1, cbegin(freqToList[1])};
}
private:
int capacity;
int minFreq;
unordered_map<int, Node> keyToNode;
unordered_map<int, list<int>> freqToList;
void touch(Node& node) {
// Update the node's frequency
const int prevFreq = node.freq;
const int newFreq = ++node.freq;
// Remove the iterator from prevFreq's list
freqToList[prevFreq].erase(node.it);
if (freqToList[prevFreq].empty()) {
freqToList.erase(prevFreq);
// Update minFreq if needed
if (prevFreq == minFreq)
++minFreq;
}
// Insert the key to the front of newFreq's list
freqToList[newFreq].push_front(node.key);
node.it = cbegin(freqToList[newFreq]);
}
};
class LFUCache {
public LFUCache(int capacity) {
this.capacity = capacity;
}
public int get(int key) {
if (!keyToVal.containsKey(key))
return -1;
final int freq = keyToFreq.get(key);
freqToLRUKeys.get(freq).remove(key);
if (freq == minFreq && freqToLRUKeys.get(freq).isEmpty()) {
freqToLRUKeys.remove(freq);
++minFreq;
}
// Increase key's freq by 1
// Add this key to next freq's list
putFreq(key, freq + 1);
return keyToVal.get(key);
}
public void put(int key, int value) {
if (capacity == 0)
return;
if (keyToVal.containsKey(key)) {
keyToVal.put(key, value);
get(key); // Update key's count
return;
}
if (keyToVal.size() == capacity) {
// Evict LRU key from the minFreq list
final int keyToEvict = freqToLRUKeys.get(minFreq).iterator().next();
freqToLRUKeys.get(minFreq).remove(keyToEvict);
keyToVal.remove(keyToEvict);
}
minFreq = 1;
putFreq(key, minFreq); // Add new key and freq
keyToVal.put(key, value); // Add new key and value
}
private int capacity;
private int minFreq = 0;
private Map<Integer, Integer> keyToVal = new HashMap<>();
private Map<Integer, Integer> keyToFreq = new HashMap<>();
private Map<Integer, LinkedHashSet<Integer>> freqToLRUKeys = new HashMap<>();
private void putFreq(int key, int freq) {
keyToFreq.put(key, freq);
freqToLRUKeys.putIfAbsent(freq, new LinkedHashSet<>());
freqToLRUKeys.get(freq).add(key);
}
}