LFU Cache
2018-11-06 20:06:04
LFU(Least Frequently Used)算法根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”。
如何高效的实现一个LFU Cache是一个难点,其实现方式要比LRU要复杂一点,问题的核心就是如果对不同的freq进行计数和维护。这里用到的思路和最大频率栈是类似的,也就是对每个freq都开辟一个Set来进行单独的维护。

为了实现的方便,我们可以在每个freq节点中放入一个LinkedHashSet,这样就可以很方便的进行编码。
public class LFUCache {
private FreqNode head;
private FreqNode tail;
private HashMap<Integer, Integer> key2val;
private HashMap<Integer, FreqNode> key2node;
private int capacity;
public LFUCache(int capacity) {
this.capacity = capacity;
this.head = new FreqNode(0);
this.tail = new FreqNode(Integer.MAX_VALUE);
this.key2val = new HashMap<>();
this.key2node = new HashMap<>();
head.next = tail;
tail.prev = head;
}
public int get(int key) {
if (capacity == 0) return -1;
if (key2val.containsKey(key)) {
int res = key2val.get(key);
increaseFreq(key);
return res;
}
return -1;
}
public void put(int key, int value) {
if (capacity == 0) return;
if (key2val.containsKey(key)) {
key2val.put(key, value);
increaseFreq(key);
}
else {
maintainSize();
key2val.put(key, value);
key2node.put(key, head);
head.keys.add(key);
increaseFreq(key);
}
}
private void increaseFreq(int key) {
FreqNode cur = key2node.get(key);
FreqNode next = null;
if (cur.next.freq == cur.freq + 1) {
next = cur.next;
}
else {
next = new FreqNode(cur.freq + 1);
next.next = cur.next;
cur.next.prev = next;
cur.next = next;
next.prev = cur;
}
next.keys.add(key);
cur.keys.remove(key);
key2node.put(key, next);
if (cur.keys.size() == 0 && cur != head) delete(cur);
}
private void maintainSize() {
if (key2val.size() >= capacity) {
FreqNode cur = head.next;
Iterator<Integer> iter = cur.keys.iterator();
int key = iter.next();
key2val.remove(key);
key2node.remove(key);
cur.keys.remove(key);
if (cur.keys.size() == 0) delete(cur);
}
}
private void delete(FreqNode node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
}
class FreqNode {
public int freq;
public FreqNode prev ;
public FreqNode next;
public LinkedHashSet<Integer> keys;
public FreqNode(int freq) {
this.freq = freq;
prev = null;
next = null;
keys = new LinkedHashSet<>();
}
}
/**
* 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);
*/
LFU Cache的更多相关文章
- [LeetCode] LFU Cache 最近最不常用页面置换缓存器
Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the f ...
- 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] 460. 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:LRU Cache,LFU Cache
在Leetcode上遇到了两个有趣的题目,分别是利用LRU和LFU算法实现两个缓存.缓存支持和字典一样的get和put操作,且要求两个操作的时间复杂度均为O(1). 首先说一下如何在O(1)时间复杂度 ...
- leetcode 460. LFU Cache
hash:存储的key.value.freq freq:存储的freq.key,也就是说出现1次的所有key在一起,用list连接 class LFUCache { public: LFUCache( ...
- [LeetCode] LRU Cache 最近最少使用页面置换缓存器
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the fol ...
- 页面置换算法 - FIFO、LFU、LRU
缓存算法(页面置换算法)-FIFO. LFU. LRU 在前一篇文章中通过leetcode的一道题目了解了LRU算法的具体设计思路,下面继续来探讨一下另外两种常见的Cache算法:FIFO. LFU ...
随机推荐
- ORA-38301:can not perform DDL/DML Over Object in Recycle Bin 11.2.0.4
我们最近有两台测试服务器在oci direct load期间出现下列异常: 从表象上看,是我们在对表执行ddl操作,确实内部也是用了truncate table XXX,可是这个XXX并不是回收站里面 ...
- windows下常用linux对应工具
tail 可从http://files.cnblogs.com/hantianwei/tail.zip下载,解压后exe,如下: e:\>tail -fn 300 tool-slow.logus ...
- 阿里云端口失效导致tomcat无法对外提供服务
下午,我们一个环境启动成功,但是却无法访问,经查看启动日志,如下: Mar 23, 2017 2:15:09 PM org.apache.coyote.http11.AbstractHttp11Pro ...
- Angular 父子组件传值
Angular 父子组件传值 @Input @Output @ViewChild 新建一个头部组件 newsheader 在主组件引用 news 组件,在news组件添加 newsheader 组 ...
- python简说(七)元组,集合
一.元组 元组也是一个list,但是它的值不能改变 定义元组的时候,只有一个元素,后面得加逗号 oracle_info = (123,) 二.集合 1.集合天生就可以去重,集合是无序的 2.#交集 r ...
- 修改userdata的分区大小【转】
本文转载自:https://blog.csdn.net/mike8825/article/details/49833833 版权声明:本文为博主原创文章,未经博主允许不得转载. https:// ...
- 关于link标签的用法, 不声明rel=stylesheet则无效? 在ff中必须声明rel属性!
void 无效的, 空的; invalid: 无效的, void 和 invalid 在表示无效的时候, 是一样的, 等同的 the treaty (条约) was declared invalid ...
- Java 使用命令对堆线程分析
一.dump基本概念 在故障定位(尤其是out of memory)和性能分析的时候,经常会用到一些文件来帮助我们排除代码问题.这些文件记录了JVM运行期间的内存占用.线程执行等情况,这就是我们常说的 ...
- 深度学习课程笔记(十七)Meta-learning (Model Agnostic Meta Learning)
深度学习课程笔记(十七)Meta-learning (Model Agnostic Meta Learning) 2018-08-09 12:21:33 The video tutorial can ...
- SHOI 2017 相逢是问候(扩展欧拉定理+线段树)
题意 https://loj.ac/problem/2142 思路 一个数如果要作为指数,那么它不能直接对模数取模,这是常识: 诸如 \(c^{c^{c^{c..}}}\) 的函数递增飞快,不是高精度 ...