请你为 最不经常使用(LFU)缓存算法设计并实现数据结构。它应该支持以下操作:get 和 put。
get(key) - 如果键存在于缓存中,则获取键的值(总是正数),否则返回 -1。
put(key, value) - 如果键已存在,则变更其值;如果键不存在,请插入键值对。当缓存达到其容量时,则应该在插入新项之前,使最不经常使用的项无效。在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,应该去除最久未使用的键。
「项的使用次数」就是自插入该项以来对其调用 get 和 put 函数的次数之和。使用次数会在对应项被移除后置为 0 。
进阶:
你是否可以在 O(1) 时间复杂度内执行两项操作?
示例:
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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lfu-cache
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
有趣的思路分析:https://leetcode-cn.com/problems/lfu-cache/solution/nei-cun-o1jiu-shuang-zhen-shi-jian-o1jiu-yong-hash/
两种链表,主链表关键字是频率,副链表关键字是key,主链表的每个节点指向一条副链表,用hashmap存节点的位置,实现O(1)增删
class LFUCache {
int capacity;
HashMap<Integer,Node> map;
HashMap<Integer,myLinkedList> Fmap;
myLinkedList Head,Tail;
public LFUCache(int capacity) {
this.capacity=capacity;
map=new HashMap<Integer,Node>();
Fmap=new HashMap<Integer,myLinkedList>();
Head=new myLinkedList();
Tail=new myLinkedList();
Head.next=Tail;
Tail.prev=Head;
Head.prev=null;
Tail.next=null;
}
public int get(int key) {
Node p=map.get(key);
if(p==null) return -1;
put(p.key,p.value);
return p.value;
}
public void put(int key, int value) {
if(capacity==0) return ;
Node p=map.get(key);
if(p!=null){
p.value=value;
//从当前频率中移除
p.delete();
myLinkedList now=Fmap.get(p.freq);
//插入新的频率
p.freq++;
myLinkedList last=Fmap.get(p.freq);
if(last==null){//没有这个频率
if(now.head.next!=now.tail){//now不空,把last插到now后面
last=new myLinkedList(p.freq);
last.insert(now);
}
else{//now空了,用last替换now(删除now)
Fmap.remove(now.freq);
last=now;
last.freq=p.freq;
}
Fmap.put(p.freq,last);//把新节点的位置放入hash
}
else if(now.head.next==now.tail){
Fmap.remove(now.freq);
now.delete();
}
p.insert(last.head);//把p插到last的表头
}
else{
if(map.size()==capacity){
//删除频率最小的尾部节点
p=Head.next.tail.prev;
p.delete();
map.remove(p.key);
myLinkedList now=Head.next;
if(now.head.next==now.tail){//如果这个频率里没有节点了,就删掉
now.delete();
Fmap.remove(now.freq);
now=new myLinkedList();
}
}
p=new Node(key,value,1);
myLinkedList F1=Fmap.get(1);
if(F1==null){
F1=new myLinkedList(1);
F1.insert(Head);
Fmap.put(1,F1);
}
p.insert(F1.head);
map.put(key,p);
}
}
}
class myLinkedList{//不同频率链表
int freq;
Node head,tail;
myLinkedList prev,next;
public myLinkedList(int freq){
this.freq=freq;
head=new Node();
tail=new Node();
head.next=tail;
tail.prev=head;
head.prev=null;
tail.next=null;
}
public myLinkedList(){
}
public void insert(myLinkedList now){//插在now后面
this.next=now.next;
this.prev=now;
now.next.prev=this;
now.next=this;
}
public void delete(){//在当前链表中删除该节点
this.next.prev=this.prev;
this.prev.next=this.next;
}
}
class Node{//同频率的链表
int key,value;
int freq;
Node prev,next;
public Node(int key,int value,int freq){
this.key=key;
this.value=value;
this.freq=freq;
}
public Node(){
}
public void insert(Node now){//插在now后面
this.next=now.next;
this.prev=now;
now.next.prev=this;
now.next=this;
}
public void delete(){//在当前链表中移除该节点
this.next.prev=this.prev;
this.prev.next=this.next;
}
}
/**
* Your LFUCache object will be instantiated and called as such:
* LFUCache obj = new LFUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/
584

被折叠的 条评论
为什么被折叠?



