• [LeetCode] 460. LFU Cache


    Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the following operations: get and put.

    get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
    put(key, value) - Set or insert the value if the key is not already present. When the cache reaches its capacity, it should invalidate the least frequently used item before inserting a new item. For the purpose of this problem, when there is a tie (i.e., two or more keys that have the same frequency), the least recently used key would be evicted.

    Note that the number of times an item is used is the number of calls to the get and put functions for that item since it was inserted. This number is set to zero when the item is removed.

    Follow up:
    Could you do both operations in O(1) time complexity?

    Example:

    LFUCache cache = new LFUCache( 2 /* capacity */ );
    
    cache.put(1, 1);
    cache.put(2, 2);
    cache.get(1);       // returns 1
    cache.put(3, 3);    // evicts key 2
    cache.get(2);       // returns -1 (not found)
    cache.get(3);       // returns 3.
    cache.put(4, 4);    // evicts key 1.
    cache.get(1);       // returns -1 (not found)
    cache.get(3);       // returns 3
    cache.get(4);       // returns 4

    LFU缓存。我就直接引用LC中文网的题干了。

    请你为 最不经常使用(LFU)缓存算法设计并实现数据结构。它应该支持以下操作:get 和 put。get(key) - 如果键存在于缓存中,则获取键的值(总是正数),否则返回 -1。

    put(key, value) - 如果键不存在,请设置或插入值。当缓存达到其容量时,则应该在插入新项之前,使最不经常使用的项无效。在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,应该去除 最近 最少使用的键。
    「项的使用次数」就是自插入该项以来对其调用 get 和 put 函数的次数之和。使用次数会在对应项被移除后置为 0 。

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/lfu-cache
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    这个题有两个函数需要实现,分别是get和put,依然是需要在O(1)时间复杂度内完成。

    这个题没有什么算法,但是通过这个题我学到了原来Java里面有一个叫做LinkedHashSet的东西。这个题既然是找LFU,最不经常使用的缓存,所以在有capacity限制的情况下,使用次数最少,频率最低的元素会被淘汰。首先我给出一个图帮助理解。

    如下分别解释一下两个函数的一些细节。

    put() - 首先看是否超过capacity,若没超过,则放入元素并get元素;如果超过了capacity,需要先找到出现次数最少的那个次数所对应的LinkedHashSet,并通过iterator删除这个LinkedHashSet中的第一个元素。这个元素就是那个在capacity临界点需要被删除的元素。如果这个元素从未被放入过,则需要把这个元素分别放入vals,counts两个hashmap和LinkedHashSet,并且标记最小出现次数为1。

    get() - 如果要找的元素不在缓存,则直接return -1。如果在缓存里面,则做两件事,1是counts++,更新其出现次数;2是更新这个元素在LinkedHashSet的位置,如果这个行为同时导致了min值的改变,也需要更新min值。

    时间O(1) - required

    空间O(n)

    Java实现

     1 class LFUCache {
     2     HashMap<Integer, Integer> vals;
     3     HashMap<Integer, Integer> counts;
     4     HashMap<Integer, LinkedHashSet<Integer>> list;
     5     int capacity;
     6     int min;
     7 
     8     public LFUCache(int capacity) {
     9         this.capacity = capacity;
    10         vals = new HashMap<>();
    11         counts = new HashMap<>();
    12         list = new HashMap<>();
    13         list.put(1, new LinkedHashSet<>());
    14         min = -1;
    15     }
    16 
    17     public int get(int key) {
    18         // corner case
    19         if (!vals.containsKey(key)) {
    20             return -1;
    21         }
    22         // normal case
    23         int count = counts.get(key);
    24         counts.put(key, count + 1);
    25         list.get(count).remove(key);
    26         if (count == min && list.get(count).size() == 0) {
    27             min++;
    28         }
    29         if (!list.containsKey(count + 1)) {
    30             list.put(count + 1, new LinkedHashSet<>());
    31         }
    32         list.get(count + 1).add(key);
    33         return vals.get(key);
    34     }
    35 
    36     public void put(int key, int value) {
    37         // corner case
    38         if (capacity <= 0) {
    39             return;
    40         }
    41         // normal case
    42         if (vals.containsKey(key)) {
    43             vals.put(key, value);
    44             get(key);
    45             return;
    46         }
    47         // if it's over the capacity
    48         if (vals.size() >= capacity) {
    49             int evit = list.get(min).iterator().next();
    50             list.get(min).remove(evit);
    51             vals.remove(evit);
    52         }
    53         // if this is never saved
    54         vals.put(key, value);
    55         counts.put(key, 1);
    56         min = 1;
    57         list.get(1).add(key);
    58     }
    59 }
    60 
    61 /**
    62  * Your LFUCache object will be instantiated and called as such:
    63  * LFUCache obj = new LFUCache(capacity);
    64  * int param_1 = obj.get(key);
    65  * obj.put(key,value);
    66  */

    LeetCode 题目总结

  • 相关阅读:
    第三届“百越杯”福建省高校网络空间安全大赛Do you know upload?
    [百度杯-二月场](Misc-Web)爆破-3
    屌丝程序员的梦想 (一)
    屌丝程序员寻爱记(一)
    MYSQL里使用正则的速度快还是使用like模糊查询语句快?
    mybatis源码探究(-)MapperProxyFactory&MapperProxy
    设计模式-责任链模式在实际项目中的使用
    java8的正确使用姿势
    Guava EventBus集成spring
    jenkins中集成commander应用
  • 原文地址:https://www.cnblogs.com/cnoodle/p/12640570.html
Copyright © 2020-2023  润新知