zoukankan      html  css  js  c++  java
  • [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 题目总结

  • 相关阅读:
    python各种类型转换-int,str,char,float,ord,hex,oct等
    python 时间戳
    在Adobe Reader中保存PDF表单数据的方法
    如何执行一个mysql的sql脚本文件
    在Apache中利用ServerAlias设置虚拟主机接收多个域名和设置域名泛解析
    utf8_general utf8_general utf8_bin区别
    CentOS 6.3 卷组挂载硬盘教程 linux的VPS如何分区
    【译】在C#中获取程序集比你想得要困难
    【译】.NET Core中的中介者模式-第二部分-Roll Your Own
    【译】.NET Core中的中介者模式-第一部分-什么是中介者
  • 原文地址:https://www.cnblogs.com/cnoodle/p/12640570.html
Copyright © 2011-2022 走看看