460. LFU缓存

请你为 最不经常使用(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);
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值