Skip to content

Commit 183aed5

Browse files
authored
Update LFU Cache.java
1 parent b7f991f commit 183aed5

File tree

1 file changed

+95
-61
lines changed

1 file changed

+95
-61
lines changed

Hard/LFU Cache.java

Lines changed: 95 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,112 @@
11
class LFUCache {
22

3-
private Map<Integer, Integer> valMap;
4-
private Map<Integer, Integer> freqMap;
5-
private Map<Integer, LinkedHashSet<Integer>> freqCountMap;
6-
private int capacity;
7-
private int minValue;
3+
private final Map<Integer, Node> keyToNodeMap;
4+
private final Map<Integer, Node[]> frequencyToNodeMap;
5+
private final Map<Integer, Integer> keyToFrequencyMap;
6+
private int capacity;
7+
private int currentCapacity;
88

9-
public LFUCache(int capacity) {
10-
valMap = new HashMap<>();
11-
freqMap = new HashMap<>();
12-
freqCountMap = new HashMap<>();
13-
this.capacity = capacity;
14-
minValue = 0;
15-
}
9+
public LFUCache(int capacity) {
10+
this.capacity = capacity;
11+
this.currentCapacity = 0;
12+
this.keyToNodeMap = new HashMap<>();
13+
this.frequencyToNodeMap = new TreeMap<>();
14+
this.keyToFrequencyMap = new HashMap<>();
15+
}
1616

17-
public int get(int key) {
18-
if (!valMap.containsKey(key)) {
19-
return -1;
20-
}
17+
public int get(int key) {
18+
if (!keyToNodeMap.containsKey(key)) {
19+
return -1;
20+
}
21+
Node node = keyToNodeMap.get(key);
22+
removeNode(node);
23+
int currentFrequency = keyToFrequencyMap.get(key);
24+
int newFrequency = currentFrequency + 1;
25+
keyToFrequencyMap.put(key, newFrequency);
26+
addNodeToFrequencyHead(node, newFrequency);
27+
return node.val;
28+
}
2129

22-
// Updating frequency
23-
int oldFreq = freqMap.get(key);
24-
freqMap.put(key, oldFreq + 1);
25-
int newFreq = freqMap.get(key);
30+
public void put(int key, int value) {
31+
if (this.capacity == 0) {
32+
return;
33+
}
34+
removeNodeIfCapacityReached(key);
35+
Node node = getNode(key, value);
36+
int newFrequency = keyToFrequencyMap.getOrDefault(key, 0) + 1;
37+
keyToFrequencyMap.put(key, newFrequency);
38+
keyToNodeMap.put(key, node);
39+
if (newFrequency > 1) {
40+
removeNode(node);
41+
}
42+
addNodeToFrequencyHead(node, newFrequency);
43+
}
2644

27-
// Removing from old frequency set
28-
LinkedHashSet<Integer> set = freqCountMap.get(oldFreq);
29-
set.remove(key);
30-
if (set.isEmpty()) {
31-
// As this was the only key with min freq so minimum frequency should be updated
32-
if (minValue == oldFreq) {
33-
minValue = oldFreq + 1;
34-
}
35-
freqCountMap.remove(oldFreq);
36-
}
37-
else {
38-
freqCountMap.put(oldFreq, set);
45+
private void removeNodeIfCapacityReached(int key) {
46+
if (!keyToNodeMap.containsKey(key) && this.currentCapacity == capacity) {
47+
for (Integer freq : frequencyToNodeMap.keySet()) {
48+
Node[] nodes = frequencyToNodeMap.get(freq);
49+
if (nodes[1].prev.val == -1) {
50+
continue;
3951
}
40-
41-
// Updating new frequency set
42-
freqCountMap.computeIfAbsent(newFreq, k -> new LinkedHashSet<>()).add(key);
43-
44-
return valMap.get(key);
52+
Node toRemove = nodes[1].prev;
53+
removeNode(toRemove);
54+
keyToNodeMap.remove(toRemove.key);
55+
keyToFrequencyMap.remove(toRemove.key);
56+
this.currentCapacity--;
57+
break;
58+
}
4559
}
60+
}
4661

47-
public void put(int key, int value) {
48-
if (capacity == 0) {
49-
return;
50-
}
51-
52-
if (get(key) != -1) {
53-
valMap.put(key, value);
54-
return;
55-
}
62+
private Node getNode(int key, int value) {
63+
Node node;
64+
if (keyToNodeMap.containsKey(key)) {
65+
node = keyToNodeMap.get(key);
66+
removeNode(node);
67+
node.val = value;
68+
} else {
69+
this.currentCapacity++;
70+
node = new Node(value, key);
71+
}
72+
return node;
73+
}
5674

57-
if (valMap.size() == capacity) {
58-
LinkedHashSet<Integer> set = freqCountMap.get(minValue);
59-
int keyToBeDeleted = set.iterator().next();
60-
valMap.remove(keyToBeDeleted);
61-
freqMap.remove(keyToBeDeleted);
62-
set.remove(keyToBeDeleted);
75+
private void addNodeToFrequencyHead(Node node, int newFrequency) {
76+
if (!frequencyToNodeMap.containsKey(newFrequency)) {
77+
Node head = new Node(-1, Integer.MIN_VALUE);
78+
Node tail = new Node(-1, Integer.MAX_VALUE);
79+
head.next = tail;
80+
tail.prev = head;
81+
frequencyToNodeMap.put(newFrequency, new Node[]{head, tail});
82+
}
83+
Node headNode = frequencyToNodeMap.get(newFrequency)[0];
84+
Node nextToHead = headNode.next;
85+
nextToHead.prev = node;
86+
node.next = nextToHead;
87+
headNode.next = node;
88+
node.prev = headNode;
89+
}
90+
91+
private void removeNode(Node node) {
92+
Node prevNode = node.prev;
93+
Node nextNode = node.next;
94+
prevNode.next = nextNode;
95+
nextNode.prev = prevNode;
96+
}
6397

64-
if (set.isEmpty()) {
65-
freqCountMap.remove(minValue);
66-
}
67-
}
98+
private static class Node {
99+
int val;
100+
int key;
101+
Node next;
102+
Node prev;
68103

69-
valMap.put(key, value);
70-
freqMap.put(key, 1);
71-
freqCountMap.computeIfAbsent(1, k -> new LinkedHashSet<>()).add(key);
72-
minValue = 1;
104+
public Node(int val, int key) {
105+
this.val = val;
106+
this.key = key;
73107
}
108+
}
74109
}
75-
76110
/**
77111
* Your LFUCache object will be instantiated and called as such:
78112
* LFUCache obj = new LFUCache(capacity);

0 commit comments

Comments
 (0)