LeetCode 460. LFU Cache LFU缓存 (C++/Java)
题目:
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)缓存的数据结构。相比LRU,LFU增加了频率这一概念,在cache满了的时候,将会把最不经常使用的缓存清除掉,在本题则是以访问频率体现的。
利用hashmap来记录当前数据{key, value}和其出现次数之间的映射,我们可以把出现频率相同的key都放到一个list集合中,再使用一个hashmap建立频率和list之间的映射。为了能够在O(1)的时间内完成操作了,要快速的定位list中key的位置,我们再用一个hashmap来建立key和freq中key的位置之间的映射。最后当然我们还需要两个变量cap和minFreq,分别来保存cache的大小,和当前最小的频率。
我们假设容量为2,先put(1, 1)和put(2, 2),此时容器的存储情况如下:
此时调用get(1,1),我们需要做的操作如下:
1.如果m中不存在key1,那么返回-1
2. 从freq中频率为1(从m中获取到的key对应的频率值)的list中将1删除
3. 将m中1对应的频率值自增1
4. 将1保存到freq中频率为2(当前频率加+1)的list的末尾
5. 在l中保存1在freq中频率为2的list中的位置
6. 如果freq中频率为minFreq的list为空,minFreq自增1
7. 返回m中1对应的value值
经过这些步骤后,我们再来看下此时内部容器情况:
此时再put(3, 3),我们需要做的操作如下:
1. 先调用get(3)返回的结果不是-1,也就是说此时cache中已经存在3这块缓存了,我们可以直接将m中3对应的value更新为当前value,并返回。
2. 如果此时m的大小大于了cap,即超过了cache的容量,则:
a)在m中移除minFreq对应的list的首元素的key。
b)在l中清除3对应的纪录
c)在freq中移除minFreq对应的list的首元素。
3. 在m中建立3的映射,即 3 -> {value 3, frequent1}
4. 在freq中频率为1的list末尾加上3
5. 在l中保存3在freq中频率为1的list中的位置
6. minFreq重置为1
此时内部容器情况:
虚线表示此步骤删去的元素。
程序:
C++
class LFUCache {
public:
LFUCache(int capacity) {
cap = capacity;
} int get(int key) {
if(m.count(key) == 0)
return -1;
freq[m[key].second].erase(l[key]);
m[key].second++;
freq[m[key].second].push_back(key);
l[key] = --freq[m[key].second].end();
if(freq[minFreq].size() == 0)
minFreq++;
return m[key].first;
} void put(int key, int value) {
if(cap <= 0)
return;
if(get(key) != -1){
m[key].first = value;
return;
}
if(m.size() >= cap){
m.erase(freq[minFreq].front());
l.erase(freq[minFreq].front());
freq[minFreq].pop_front();
}
m[key] = make_pair(value, 1);
freq[1].push_back(key);
l[key] = --freq[1].end();
minFreq = 1;
} private:
int cap, minFreq;
unordered_map<int, pair<int, int>> m;
unordered_map<int, list<int>> freq;
unordered_map<int, list<int>::iterator> l;
}; /**
* 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);
*/
Java
public class LFUCache { public LFUCache(int capacity) {
cap = capacity;
map = new HashMap<>();
freq = new HashMap<>();
list = new HashMap<>();
minFreq = 1;
}
public int get(int key) {
if(!map.containsKey(key))
return -1;
int count = freq.get(key);
list.get(count).remove(key);
freq.put(key, count + 1);
if(list.get(minFreq).size() == 0)
minFreq++;
if(!list.containsKey(count + 1)){
LinkedHashSet<Integer> set = new LinkedHashSet<Integer>();
set.add(key);
list.put(count+1, set);
}else{
list.get(count+1).add(key);
}
return map.get(key);
}
public void put(int key, int value) {
if(cap <= 0)
return;
if(get(key) != -1){
map.put(key, value);
return;
}
if(map.size() >= cap){
Integer removeKey = list.get(minFreq).iterator().next();
map.remove(removeKey);
list.get(minFreq).remove(removeKey);
freq.remove(removeKey);
}
//System.out.println(map.toString());
map.put(key, value);
freq.put(key, 1);
if(!list.containsKey(1)){
LinkedHashSet<Integer> set = new LinkedHashSet<Integer>();
set.add(key);
list.put(1, set);
}else{
list.get(1).add(key);
}
minFreq = 1;
} private int cap;
private int minFreq;
private HashMap<Integer, Integer> map;
private HashMap<Integer, Integer> freq;
private HashMap<Integer, LinkedHashSet<Integer>> list;
} /**
* 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);
*/
LeetCode 460. LFU Cache LFU缓存 (C++/Java)的更多相关文章
- LeetCode:146_LRU cache | LRU缓存设计 | Hard
题目:LRU cache Design and implement a data structure for Least Recently Used (LRU) cache. It should su ...
- [LeetCode] 460. LFU Cache 最近最不常用页面置换缓存器
Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the f ...
- [LeetCode] LFU Cache 最近最不常用页面置换缓存器
Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the f ...
- leetcode 146. LRU Cache 、460. LFU Cache
LRU算法是首先淘汰最长时间未被使用的页面,而LFU是先淘汰一定时间内被访问次数最少的页面,如果存在使用频度相同的多个项目,则移除最近最少使用(Least Recently Used)的项目. LFU ...
- Leetcode: LFU Cache && Summary of various Sets: HashSet, TreeSet, LinkedHashSet
Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the f ...
- LeetCode LFU Cache
原题链接在这里:https://leetcode.com/problems/lfu-cache/?tab=Description 题目: Design and implement a data str ...
- LeetCode之LRU Cache 最近最少使用算法 缓存设计
设计并实现最近最久未使用(Least Recently Used)缓存. 题目描述: Design and implement a data structure for Least Recently ...
- [LeetCode] 146. LRU Cache 最近最少使用页面置换缓存器
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the fol ...
- LFU Cache
2018-11-06 20:06:04 LFU(Least Frequently Used)算法根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”. ...
- LRU缓存实现(Java)
LRU Cache的LinkedHashMap实现 LRU Cache的链表+HashMap实现 LinkedHashMap的FIFO实现 调用示例 LRU是Least Recently Used 的 ...
随机推荐
- 探索Kimi智能助手:如何用超长文本解锁高效信息处理新境界
目前,Kimi备受瞩目,不仅在社交平台上引起了广泛关注,而且在解决我们的实际问题方面也显示出了巨大潜力.其支持超长文本的特性使得我们能够更加灵活地配置信息,避免了频繁与向量数据库进行交互以及编写提示词 ...
- Spring 源码阅读(一)环境搭建
注意事项: 使用 2024-03-14 发布的 Spring 5.3.33 版本 IDE 工具使用了 Intellij IDEA,同时为了简化不必要的内容没单独配置 Gradle 环境 JDK 版本采 ...
- 牛客网-SQL专项训练7
①SQL语言可以分为多个类别,那么不属于数据操纵语言DML的是(B) 解析: SQL语言共分为四大类:数据查询语言DQL,数据操纵语言DML,数据定义语言DDL,数据控制语言DCL. 1. 数据查询语 ...
- 云原生消息队列Pulsar浅析
简介: 云原生消息队列Pulsar浅析 一.前言 Pulsar是一个多租户,高性能的服务间消息解决方案.最初由Yahoo开发,现在由Apache Software Foundation负责.Pulsa ...
- 数百万台车联网设备同时在线0故障,中瑞集团的云原生探索之路 | 云原生Talk
简介: 在保持对业界趋势调度关注的同时,始终选用最适合自身的技术,这可能是中瑞能在车联网领域引领行业的重要原因之一,正如中瑞CTO所说"阿里云云原生产品体系带给我们的,不是单纯的IT工具,而 ...
- 云效DevOps实践-如何基于云效实现测试自动化集成和分析
简介: 对于现代软件研发来说,持续.快速.高质量.低风险地交付需求特性,是业务对研发的主要诉求.而要做到这一点,除了要有良好的架构设计.卓越的工程能力,快速可靠的测试反馈也是其非常重要的一环,达到这一 ...
- 阿里云图数据库GDB V3引擎发布,加速开启“图智”未来
简介:无论是学术界还是产业界,都对图数据库有比较高的预期.Gartner发布的<2021年十大数据和分析技术趋势>中提到:"到2025年图技术在数据和分析创新中的占比将从202 ...
- 一文带你了解企业上云数据分析首选产品Quick BI
简介: 阿里云Quick BI再度入选,并继续成为该领域唯一入选魔力象限的中国企业,文章将为大家详细介绍上云数据分析首选产品 Quick BI的核心能力. 日前,国际权威分析机构Gartner发布20 ...
- Serverless 时代下大规模微服务应用运维的最佳实践
简介: 原来的微服务用户需要自建非常多的组件,包括 PaaS 微服务一些技术框架,运维 IaaS.K8s,还包括可观测组件等.SAE 针对这些方面都做了整体的解决方案,使用户只需要关注自己的业务系统, ...
- 一文详解Redis中BigKey、HotKey的发现与处理
简介: 在Redis的使用过程中,我们经常会遇到BigKey(下文将其称为"大key")及HotKey(下文将其称为"热key").大Key与热Key如果未能及 ...