设计并实现最不经常使用(LFU)缓存的数据结构。它应该支持以下操作:get 和 put

get(key) - 如果键存在于缓存中,则获取键的值(总是正数),否则返回 -1。
put(key, value) - 如果键不存在,请设置或插入值。当缓存达到其容量时,它应该在插入新项目之前,使最不经常使用的项目无效。在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,最近最少使用的键将被去除。

进阶:
你是否可以在 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

思路:这道题可以参考上一篇LRU:http://www.cnblogs.com/DarrenChan/p/8744354.html

LFU多了一个频率值的计算,只有当频率值相同的时候,才按照LRU那种方式进行排列,即最近最不经常使用的淘汰。

借鉴一种思想,因为时间复杂度是O(1),所以不能用循环遍历,方法就是采用3个HashMap和1个LinkedHashSet。

第一个hashMap存储put进去的key和value,第二个HashMap存储每个key的频率值,第三个hashMap存储每个频率的相应的key的值的集合。LinkedHashSet存储key的集合,这里用HashSet是因为其是由HashMap底层实现的,可以O(1)时间复杂度查找元素,而且linked是有序的,同一频率值越往后越最近访问。

直接上代码:

import java.util.HashMap;
import java.util.LinkedHashSet; class LFUCache { public int capacity;//容量大小
public HashMap<Integer, Integer> map = new HashMap<>();//存储put进去的key和value
public HashMap<Integer, Integer> frequent = new HashMap<>();//存储每个key的频率值
//存储每个频率的相应的key的值的集合,这里用HashSet是因为其是由HashMap底层实现的,可以O(1)时间复杂度查找元素
//而且linked是有序的,同一频率值越往后越最近访问
public HashMap<Integer, LinkedHashSet<Integer>> list = new HashMap<>();
int min = -1;//标记当前频率中的最小值 public LFUCache(int capacity) {
this.capacity = capacity;
} public int get(int key) {
if(!map.containsKey(key)){
return -1;
}else{
int value = map.get(key);//获取元素的value值
int count = frequent.get(key);
frequent.put(key, count + 1); list.get(count).remove(key);//先移除当前key //更改min的值
if(count == min && list.get(count).size() == 0)
min++; LinkedHashSet<Integer> set = list.containsKey(count + 1) ? list.get(count + 1) : new LinkedHashSet<Integer>();
set.add(key);
list.put(count + 1, set); return value;
} } public void put(int key, int value) {
if(capacity <= 0){
return;
}
//这一块跟get的逻辑一样
if(map.containsKey(key)){
map.put(key, value);
int count = frequent.get(key);
frequent.put(key, count + 1); list.get(count).remove(key);//先移除当前key //更改min的值
if (count == min && list.get(count).size() == 0)
min++; LinkedHashSet<Integer> set = list.containsKey(count + 1) ? list.get(count + 1) : new LinkedHashSet<Integer>();
set.add(key);
list.put(count + 1, set);
}else{
if(map.size() >= capacity){
Integer removeKey = list.get(min).iterator().next();
list.get(min).remove(removeKey);
map.remove(removeKey);
frequent.remove(removeKey);
}
map.put(key, value);
frequent.put(key, 1);
LinkedHashSet<Integer> set = list.containsKey(1) ? list.get(1) : new LinkedHashSet<Integer>();
set.add(key);
list.put(1, set); min = 1;
} } public static void main(String[] args) {
LFUCache lfuCache = new LFUCache(2);
lfuCache.put(2, 1);
lfuCache.put(3, 2);
System.out.println(lfuCache.get(3));
System.out.println(lfuCache.get(2));
lfuCache.put(4, 3);
System.out.println(lfuCache.get(2));
System.out.println(lfuCache.get(3));
System.out.println(lfuCache.get(4));
}
}

原题链接:https://leetcode-cn.com/problems/lfu-cache/description/

[LeetCode]460.LFU缓存机制的更多相关文章

  1. [Leetcode]146.LRU缓存机制

    Leetcode难题,题目为: 运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key ...

  2. Leetcode 146. LRU 缓存机制

    前言 缓存是一种提高数据读取性能的技术,在计算机中cpu和主内存之间读取数据存在差异,CPU和主内存之间有CPU缓存,而且在内存和硬盘有内存缓存.当主存容量远大于CPU缓存,或磁盘容量远大于主存时,哪 ...

  3. LeetCode 146. LRU缓存机制(LRU Cache)

    题目描述 运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 (k ...

  4. Java实现 LeetCode 146 LRU缓存机制

    146. LRU缓存机制 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - ...

  5. [LeetCode] 460. LFU Cache 最近最不常用页面置换缓存器

    Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the f ...

  6. leetcode 460. LFU Cache

    hash:存储的key.value.freq freq:存储的freq.key,也就是说出现1次的所有key在一起,用list连接 class LFUCache { public: LFUCache( ...

  7. leetcode:146. LRU缓存机制

    题目描述: 运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 ( ...

  8. leetcode 146. LRU Cache 、460. LFU Cache

    LRU算法是首先淘汰最长时间未被使用的页面,而LFU是先淘汰一定时间内被访问次数最少的页面,如果存在使用频度相同的多个项目,则移除最近最少使用(Least Recently Used)的项目. LFU ...

  9. leetcode LRU缓存机制(list+unordered_map)详细解析

    运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 (key) 存 ...

随机推荐

  1. Android RGB颜色查询对照表

    因为兼容性问题,色阶板功能只能在IE浏览器中运行 RGB颜色对照表   #FFFFFF   #FFFFF0   #FFFFE0   #FFFF00   #FFFAFA   #FFFAF0   #FFF ...

  2. Java代码通过API操作HBase的最佳实践

    HBase提供了丰富的API.这使得用Java连接HBase非常方便. 有时候大家会使用HTable table=new HTable(config,tablename);的方式来实例化一个HTabl ...

  3. 基础004_V7-DSP Slice

    主要参考ug479.pdf.之前的文章:FIR调用DSP48E_05.本文主要记录基本用法. 一.DSP48核 A-参数说明 instrctions,多个功能,通过sel选用 目前没发现C勾选与否,有 ...

  4. gitlab 迁移、升级打怪之路:8.8.5--> 8.10.8 --> 8.17.8 --> 9.5.9 --> 10.1.4 --> 10.2.5

    gitlab 迁移.升级打怪之路:8.8.5--> 8.10.8 --> 8.17.8 --> 9.5.9 --> 10.1.4 --> 10.2.5 gitlab 数据 ...

  5. [svc]NFS存储企业场景及nfs最佳实战探究

    办公网络里人一般系统用共享,尤其是财务, 他们喜欢直接点开编辑. 而不喜欢ftp nfs在网站架构中的用途 注: 如果pv量少,则放在一台机器上速度更快,如果几千万pv,则存储分布式部署. 网站架构中 ...

  6. vue2.x 路由懒加载 优化打包体积

    当打包构建应用时,Javascript 包会变得非常大,影响页面加载.如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了. 结合 Vue 的异步组 ...

  7. C#中int、long、float、double、decimal最大值最小值

    最近在将java上写的一个简单的表达式求值计算器移植到Windows Phone 8,java中double的精度问题是很明显的,解决办法是改用BigDecimal类.所以觉得C#中用double也是 ...

  8. ngx_http_stub_status_module

    ngx_http_stub_status_module是一个Nginx的内置 HTTP模块,该模块可以提供Nginx的状态信息.编译的时候 需指定加载该模块: --with-http_stub_sta ...

  9. python--使用MySQL数据库

    1.安装mysqlsudo apt-get install mysql-server Sudo apt-get install mysql-client 2.安装MySQL-python驱动sudo ...

  10. 【Linux】了解服务器的情况

    Java程序大多数都部署在Unix环境,而环境的稳定性对于部署的应用至关重要,所以Java开发人员需知道了解Unix环境的命令. 系统版本 查看系统版本 [root@localhost third_p ...