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 ...
随机推荐
- 01: flask基础
1.1 flask介绍 参考博客: https://www.cnblogs.com/sss4/p/8097653.html 1.django.tornado.flask比较 1. Django:1 ...
- jtl转化成CSV格式的聚合报告
1: 从官网下载4.0 的zip 包解压缩,下载地址: https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-4.0.zip ,假 ...
- python 之 函数的参数
函数的参数好几种类型:包括位置参数.默认参数.可变参数.关键字参数.命名关键字参数. 廖大神python学习笔记,大神网站:百度搜索“廖雪峰的官网” 1.位置参数:调用函数时根据函数定义的参数位置来传 ...
- Wxpython零基础制作计算器
本文关于Wxpython零基础利用python3.6在pycharm下制作计算器,文章末尾有免费源代码供下载 以后同步更新到博客园和这个网站,www.empirefree.top, 这个网站备案号没有 ...
- Python3 tkinter基础 Listbox height 显示行数的上限
Python : 3.7.0 OS : Ubuntu 18.04.1 LTS IDE : PyCharm 2018.2.4 Conda ...
- Flask学习【第10篇】:自定义Form组件
wtforms源码流程 实例化流程分析 1 # 源码流程 2 1. 执行type的 __call__ 方法,读取字段到静态字段 cls._unbound_fields 中: meta类读取到cls._ ...
- 从Hello World说起(Dart)到“几乎所有东西都是Widget”小部件。
import 'package:flutter/material.dart'; void main() => runApp(new MyApp()); class MyApp extends S ...
- jvm:分析工具
bin/jvisualvm.exe 可查看类实例数 bin/jconsole.exe 监控线程,堆,等 http://blog.csdn.net/yaowj2/article/details/7107 ...
- [午间休息] - 午间codewars活跃脑袋
https://www.codewars.com/kata/51f2b4448cadf20ed0000386/javascript 中午是一个易困的时间段.如果其它人不睡觉还好. 这个js题目就是说如 ...
- ETCD原理
etcd:从应用场景到实现原理的全方位解读 从etcd的架构开始,深入到源码中解析etcd 1 架构 从etcd的架构图中我们可以看到,etcd主要分为四个部分. HTTP Server: 用于处理用 ...