import
java.util.*;
class
LFUCache<K, V>
{
private
final
int
capacity;
private
final
Map<K, V> cache;
private
final
Map<K, Integer> frequencyMap;
private
final
TreeMap<Integer, LinkedHashSet<K>> frequencyCounter;
public
LFUCache(
int
capacity) {
this
.capacity = capacity;
this
.cache =
new
HashMap<>();
this
.frequencyMap =
new
HashMap<>();
this
.frequencyCounter =
new
TreeMap<>();
}
public
V get(K key) {
if
(!cache.containsKey(key)) {
return
null
;
}
int
frequency = frequencyMap.get(key);
frequencyMap.put(key, frequency +
1
);
frequencyCounter.get(frequency).remove(key);
if
(frequencyCounter.get(frequency).isEmpty()) {
frequencyCounter.remove(frequency);
}
frequencyCounter.computeIfAbsent(frequency +
1
, k ->
new
LinkedHashSet<>()).add(key);
return
cache.get(key);
}
public
void
put(K key, V value) {
if
(capacity <=
0
) {
return
;
}
if
(cache.size() >= capacity) {
int
lowestFrequency = frequencyCounter.firstKey();
K leastFrequentKey = frequencyCounter.get(lowestFrequency).iterator().next();
cache.remove(leastFrequentKey);
frequencyMap.remove(leastFrequentKey);
frequencyCounter.get(lowestFrequency).remove(leastFrequentKey);
if
(frequencyCounter.get(lowestFrequency).isEmpty()) {
frequencyCounter.remove(lowestFrequency);
}
}
cache.put(key, value);
frequencyMap.put(key,
1
);
frequencyCounter.computeIfAbsent(
1
, k ->
new
LinkedHashSet<>()).add(key);
}
}
public
class
LFUCacheExample
{
public
static
void
main(String[] args)
{
LFUCache<Integer, String> lfuCache =
new
LFUCache<>(
3
);
lfuCache.put(
1
,
"One"
);
lfuCache.put(
2
,
"Two"
);
System.out.println(
"Get 1: "
+ lfuCache.get(
1
));
lfuCache.put(
3
,
"Three"
);
lfuCache.put(
4
,
"Four"
);
System.out.println(
"Get 2: "
+ lfuCache.get(
2
));
System.out.println(
"Get 3: "
+ lfuCache.get(
3
));
System.out.println(
"Get 4: "
+ lfuCache.get(
4
));
}
}