此题解法参考 https://developer.aliyun.com/article/854931
代码参考我的上一篇LRU Cache
首先定义了两个哈希表,第一个哈希表用于存储节点,帮助快速找出节点,第二个哈希表用于存储各个使用次数下都有那些节点。
同时为了快速找出使用次数最少的节点定义了一个TreeSet
public class LFUCache {
private int capacity;
// 存储节点
private HashMap<Integer,Node> map = null;
// 存储使用频率
private HashMap<Integer,DoubleLinkedList> fre = null;
private TreeSet<Integer> frequencies; // 维护当前存在的频率
// 定义一个双向链表
class DoubleLinkedList{
Node head;
Node tail;
public DoubleLinkedList() {
head = new Node(-1, -1);
tail = new Node(-1, -1);
head.next = tail;
tail.pre = head;
}
public void insert(Node node) {
// 头插法
node.next = head.next;
node.pre = head;
head.next.pre = node;
head.next = node;
}
public void remove(Node node){
// 尾插法
Node pre = node.pre;
Node ne = node.next;
pre.next = ne;
ne.pre = pre;
}
public Node getLastNode(){
return tail.pre;
}
public boolean empty(){
if (head.next == tail){
return true;
}else{
return false;
}
}
}
class Node{
int key;
int val;
int freq;
Node next;
Node pre;
public Node(int key,int value){
this.key = key;
this.val = value;
this.freq = 1;
}
}
public LFUCache(int capacity) {
this.capacity = capacity;
this.map = new HashMap<>();
this.fre = new HashMap<>();
this.frequencies = new TreeSet<>();
}
public int get(int key) {
// 获取节点
if (map.containsKey(key)){
Node node = map.get(key);
remove(node);
node.freq++;
push(node);
return node.val;
}else{
return -1;
}
}
public void push(Node node){
// 插入到freq中
map.put(node.key,node);
int frequence = node.freq;
frequencies.add(frequence);
if (fre.containsKey(frequence)){
DoubleLinkedList linkedList = this.fre.get(frequence);
linkedList.insert(node);
}else{
// 首先创建头节点然后插入
DoubleLinkedList linkedList = new DoubleLinkedList();
this.fre.put(frequence,linkedList);
linkedList.insert(node);
}
}
public void remove(Node node) {
int frequence = node.freq;
DoubleLinkedList linkedList = fre.get(frequence); // 用频率作为键
if (linkedList == null) return;
linkedList.remove(node);
if (linkedList.empty()) {
fre.remove(frequence);
frequencies.remove(frequence);
}
map.remove(node.key);
}
public void put(int key, int value) {
if (capacity <= 0) return;
if (map.containsKey(key)) {
Node node = map.get(key);
node.val = value;
get(key);
return;
}
if (map.size() >= capacity) {
int minFreq = frequencies.first();
if (fre.containsKey(minFreq)) {
DoubleLinkedList list = fre.get(minFreq);
if (!list.empty()) {
Node lastNode = list.getLastNode();
remove(lastNode);
}
}
}
Node newNode = new Node(key, value);
push(newNode);
frequencies.add(1);
}
}