Title Description
Design and implement the least frequently used (LFU) cache data structure. It should support the following operations: get and put.
get (key) - if the key exists in the cache, then get the value (always positive) key, otherwise -1.
put (key, value) - if the key does not exist, or insert set value. When the cache reaches its capacity, it should be in before inserting a new project, the project is not the most frequently used is invalid. In this problem, when there is a tie (i.e., two or more keys having the same frequency), the least recently used key is removed.
The title comes from the leetcode, click to enter
Read title
Example:
LFUCache cache = new LFUCache( 2 /* capacity (缓存容量) */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 去除 key 2
cache.get(2); // 返回 -1 (未找到key 2)
cache.get(3); // 返回 3
cache.put(4, 4); // 去除 key 1
cache.get(1); // 返回 -1 (未找到 key 1)
cache.get(3); // 返回 3
cache.get(4); // 返回 4
Designed as follows:
Code
LFUCache class
public class LFUCache {
private int cap; // 缓存总容量
private int size; // 当前缓存使用量
private HashMap<Integer, Node> cache; // 缓存Map
private HashMap<Integer, ArrayList<Node>> freqNodes; // 记录使用次数
// 打印当前缓存内容 测试用
public void printCache(){
for (Map.Entry<Integer, Node> entry : cache.entrySet()){
System.out.print(entry.getKey()+" ");
}
System.out.println();
}
public LFUCache(int capacity) {
this.cap = capacity;
this.cache = new HashMap<Integer, Node>(capacity);
this.freqNodes = new HashMap<Integer, ArrayList<Node>>();
}
public int get(int key) {
Node node = cache.get(key);
if (node == null) {
return -1;
}
node.freq++;
// 次数有变化,需要更新记录使用次数的Map
adjustPosition(node);
return node.value;
}
private void adjustPosition(Node node) {
if (freqNodes.containsKey(node.freq - 1)) {
freqNodes.get(node.freq - 1).remove(node);
// list为空时需要将它从记录使用次数的map中移除
if (freqNodes.get(node.freq - 1).size() == 0) {
freqNodes.remove(node.freq - 1);
}
}
// 将node加到新的list,如果不存在需要新建
if (freqNodes.containsKey(node.freq)) {
freqNodes.get(node.freq).add(node);
} else {
ArrayList<Node> newNodes = new ArrayList<Node>();
newNodes.add(node);
freqNodes.put(node.freq, newNodes);
}
}
public int getMinReq() {
int req = 0;
boolean flag = true;
// 循环获取最小key,没有什么好说的
for (Map.Entry<Integer, ArrayList<Node>> entry : freqNodes.entrySet()) {
if(flag){
req = entry.getKey();
flag = false;
}else{
req = Integer.min(req, entry.getKey());
}
}
return rep;
}
public void put(int key, int value) {
// 容量为0无法存储
if (cap == 0) return;
// 判断是否已经存在
Node node = cache.get(key);
if (node == null) {
// 不存在的情况,需要判断缓存是否已满,没有满,直接加入,若满了,需要找到使用次数最少最近调用时间最靠后的
if (size == cap) {
// 找到使用次数最少且最近一次使用时间最长的元素
int remove = getMinReq();
int k = freqNodes.get(remove).get(0).key;
// 将找到的元素从原来的list中删除
freqNodes.get(remove).remove(0);
// 从缓存中删除
cache.remove(k);
node = new Node(key,value);
// 新增时,需要更新记录使用次数的Map
adjustPosition(node);
cache.put(key, node);
} else {
Node newNode = new Node(key, value);
// 新增时,需要更新记录使用次数的Map
adjustPosition(newNode);、
// 加入缓存
cache.put(key, newNode);
// 当前缓存大小增加
size++;
}
} else {
// 已存在的情况,更新调用次数,更新值
node.value = value;
node.freq++;
// 次数有变化,需要更新记录使用次数的Map
adjustPosition(node);
}
}
}
Node Deliverable
class Node {
int key;
int value;
int freq = 0;
public Node(int key, int value) {
this.key = key;
this.value = value;
}
public Node() {
}
}
test
public class Test {
public static void main(String[] args) {
LFUCache lfuCache = new LFUCache(5);
lfuCache.put(1,1);
lfuCache.put(2,2);
lfuCache.put(3,3);
lfuCache.put(4,4);
lfuCache.put(5,5);
System.out.println(lfuCache.get(1));
System.out.println(lfuCache.get(2));
System.out.println(lfuCache.get(4));
System.out.println(lfuCache.get(5));
lfuCache.put(6,6);
System.out.println("push(6,6)此时cache:");
lfuCache.printCache();
System.out.println(lfuCache.get(3));
System.out.println(lfuCache.get(6));
System.out.println("================此时剩余12456 均只调用一次 1距离上次调用时间最久================");
lfuCache.put(7,7); // 此时应该为 24567
System.out.println("push(7,7),此时cache:");
lfuCache.printCache();
System.out.println(lfuCache.get(1));// 应为 -1
}
}
- operation result: