Skip to content

Commit 46e7636

Browse files
edit 460
1 parent 14ab484 commit 46e7636

File tree

3 files changed

+111
-33
lines changed

3 files changed

+111
-33
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ Your ideas/fixes/algorithms are more than welcome!
163163
|463|[Island Perimeter](https://leetcode.com/problems/island-perimeter/)|[Solution](../master/src/main/java/com/fishercoder/solutions/_463.java)| O(m*n)|O(1) | Easy|
164164
|462|[Minimum Moves to Equal Array Elements II](https://leetcode.com/problems/minimum-moves-to-equal-array-elements-ii/)|[Solution](../master/src/main/java/com/fishercoder/solutions/_462.java) | O(nlogn) |O(1) | Medium|
165165
|461|[Hamming Distance](https://leetcode.com/problems/hamming-distance/)|[Solution](../master/src/main/java/com/fishercoder/solutions/_461.java) | O(n) |O(1) | Easy|
166-
|460|[LFU Cache](https://leetcode.com/problems/lfu-cache/)|[Solution](../master/src/main/java/com/fishercoder/solutions/_460.java) | O(?) |O(?) | Hard| Design
166+
|460|[LFU Cache](https://leetcode.com/problems/lfu-cache/)|[Solution](../master/src/main/java/com/fishercoder/solutions/_460.java) | O(1) |O(n) | Hard| Design, LinkedHashMap, HashMap
167167
|459|[Repeated Substring Pattern](https://leetcode.com/problems/repeated-substring-pattern/)|[Solution](../master/src/main/java/com/fishercoder/solutions/_459.java)| O(n)|O(n) | Easy| KMP
168168
|458|[Poor Pigs](https://leetcode.com/problems/poor-pigs/)|[Solution](../master/src/main/java/com/fishercoder/solutions/_458.java) | O(1) |O(1) | Easy| Math
169169
|456|[132 Pattern](https://leetcode.com/problems/132-pattern/)|[Solution](../master/src/main/java/com/fishercoder/solutions/_456.java) | O(n) |O(n) | Medium| Stack

src/main/java/com/fishercoder/solutions/_460.java

Lines changed: 84 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,36 @@
33
import java.util.HashMap;
44
import java.util.LinkedHashSet;
55

6+
/**460. LFU Cache
7+
* Design and implement a data structure for Least Frequently Used (LFU) cache.
8+
* It should support the following operations: get and put.
9+
10+
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
11+
put(key, value) - Set or insert the value if the key is not already present. When the cache reaches its capacity,
12+
it should invalidate the least frequently used item before inserting a new item.
13+
For the purpose of this problem, when there is a tie (i.e., two or more keys that have the same frequency),
14+
the least recently used key would be evicted.
15+
16+
Follow up:
17+
Could you do both operations in O(1) time complexity?
18+
19+
Example:
20+
21+
LFUCache cache = new LFUCache( 2 /* capacity );
22+
23+
cache.put(1, 1);
24+
cache.put(2, 2);
25+
cache.get(1); // returns 1
26+
cache.put(3, 3); // evicts key 2
27+
cache.get(2); // returns -1 (not found)
28+
cache.get(3); // returns 3.
29+
cache.put(4, 4); // evicts key 1.
30+
cache.get(1); // returns -1 (not found)
31+
cache.get(3); // returns 3
32+
cache.get(4); // returns 4
33+
34+
*/
35+
636
public class _460 {
737
/**
838
* Wikipedia: The simplest method to employ an LFU algorithm is to assign a counter to every
@@ -14,53 +44,75 @@ public class _460 {
1444
* Policy to handle frequency ties: based on timestamp, the entries that get set into cache earlier will be evicted first.
1545
*/
1646

17-
class LFUCache {
47+
public static class LFUCache {
1848
/**credit: https://discuss.leetcode.com/topic/69737/java-o-1-very-easy-solution-using-3-hashmaps-and-linkedhashset/2*/
19-
HashMap<Integer, Integer> vals;
20-
HashMap<Integer, Integer> counts;
21-
HashMap<Integer, LinkedHashSet<Integer>> lists;
49+
50+
HashMap<Integer, Integer> keyToValue;/**key is the key, value is the value*/
51+
HashMap<Integer, Integer> keyToCount;/**key is the key, value if the count of the key/value pair*/
52+
HashMap<Integer, LinkedHashSet<Integer>> countToLRUKeys;
53+
/**key is count, value is a set of keys that have the same key, but keeps insertion order*/
2254
int cap;
23-
int min = -1;
55+
int minimumCount;
56+
2457
public LFUCache(int capacity) {
25-
cap = capacity;
26-
vals = new HashMap<>();
27-
counts = new HashMap<>();
28-
lists = new HashMap<>();
29-
lists.put(1, new LinkedHashSet<>());
58+
this.minimumCount = -1;
59+
this.cap = capacity;
60+
this.keyToValue = new HashMap<>();
61+
this.keyToCount = new HashMap<>();
62+
this.countToLRUKeys = new HashMap<>();
63+
this.countToLRUKeys.put(1, new LinkedHashSet<>());
3064
}
3165

3266
public int get(int key) {
33-
if(!vals.containsKey(key))
67+
if (!keyToValue.containsKey(key)) {
3468
return -1;
35-
int count = counts.get(key);
36-
counts.put(key, count+1);
37-
lists.get(count).remove(key);
38-
if(count==min && lists.get(count).size()==0)
39-
min++;
40-
if(!lists.containsKey(count+1))
41-
lists.put(count+1, new LinkedHashSet<>());
42-
lists.get(count+1).add(key);
43-
return vals.get(key);
69+
}
70+
int count = keyToCount.get(key);
71+
keyToCount.put(key, count + 1);
72+
countToLRUKeys.get(count).remove(key);
73+
74+
if (count == minimumCount && countToLRUKeys.get(count).size() == 0) {
75+
/**This means this key's count equals to current minimumCount
76+
* AND
77+
* this count doesn't have any entries in the cache.
78+
* So, we'll increment minimumCount by 1 to get the next LFU cache entry
79+
* when we need to evict.*/
80+
minimumCount++;
81+
}
82+
83+
if (!countToLRUKeys.containsKey(count + 1)) {
84+
countToLRUKeys.put(count + 1, new LinkedHashSet<>());
85+
}
86+
countToLRUKeys.get(count + 1).add(key);
87+
88+
return keyToValue.get(key);
4489
}
4590

4691
public void put(int key, int value) {
47-
if(cap<=0)
92+
if (cap <= 0) {
4893
return;
49-
if(vals.containsKey(key)) {
50-
vals.put(key, value);
94+
}
95+
96+
if (keyToValue.containsKey(key)) {
97+
/**If the key is already in the cache, we can simply overwrite this entry;
98+
* then call get(key) which will do the update work.*/
99+
keyToValue.put(key, value);
51100
get(key);
52101
return;
53102
}
54-
if(vals.size() >= cap) {
55-
int evit = lists.get(min).iterator().next();
56-
lists.get(min).remove(evit);
57-
vals.remove(evit);
103+
104+
/**If the key is not in the cache, we'll check the size first, evict the LFU entry first,
105+
* then insert this one into cache.*/
106+
if (keyToValue.size() >= cap) {
107+
int evit = countToLRUKeys.get(minimumCount).iterator().next();
108+
countToLRUKeys.get(minimumCount).remove(evit);
109+
keyToValue.remove(evit);
58110
}
59-
vals.put(key, value);
60-
counts.put(key, 1);
61-
min = 1;
62-
lists.get(1).add(key);
111+
keyToValue.put(key, value);
112+
keyToCount.put(key, 1);
113+
countToLRUKeys.get(1).add(key);/**Because we put this key/value into cache for the first time, so its count is 1*/
114+
minimumCount = 1;/**For the same above reason, minimumCount is of course 1*/
63115
}
64116
}
65-
117+
66118
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.fishercoder;
2+
3+
import com.fishercoder.solutions._460;
4+
import org.junit.Test;
5+
6+
import static org.junit.Assert.assertEquals;
7+
8+
public class _460Test {
9+
10+
private static _460.LFUCache lfuCache;
11+
12+
@Test
13+
public void test1(){
14+
lfuCache = new _460.LFUCache(2);
15+
lfuCache.put(1, 1);
16+
lfuCache.put(2, 2);
17+
assertEquals(1, lfuCache.get(1));
18+
lfuCache.put(3, 3);
19+
assertEquals(-1, lfuCache.get(2));
20+
assertEquals(3, lfuCache.get(3));
21+
lfuCache.put(4, 4);
22+
assertEquals(-1, lfuCache.get(1));
23+
assertEquals(3, lfuCache.get(3));
24+
assertEquals(4, lfuCache.get(4));
25+
}
26+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy