LRU 算法的淘汰策略是 Least Recently Used,也就是每次淘汰那些最久没被使⽤的数据;
⽽ LFU 算法的淘汰策略是 Least Frequently Used,也就是每次淘汰那些使⽤次数最少的数据。

460. LFU缓存




解法:哈希链表+哈希表
LFU和LRU的主要区别在于缓存淘汰机制不同,前者是淘汰使用频率最低的数据,后者是淘汰最早使用的数据。
原先LRU算法的核心内容哈希链表,只能解决时序问题,无法解决频率信息。因此需要重新进行设计,实现LFU算法需要满足以下几个条件:
1、调⽤ get(key) ⽅法时,要返回该 key 对应的 val。
2、只要⽤ get 或者 put ⽅法访问⼀次某个 key,该 key 的 freq 就要加⼀。
3、如果在容量满了的时候进⾏插⼊,则需要将 freq 最⼩的 key 删除,如果最⼩的 freq 对应多个 key,则删除其中最旧的那⼀个。
针对1和2,我们可以通过维护相应的哈希表来解决,对于3,其有3个要注意的点,分别是最小freq,每个freq对应key,当freq相同时考虑时序。该实现为LFU算法核心,具体如下:
3.1、⾸先,肯定是需要 freq 到 key 的映射,⽤来找到 freq 最⼩的 key。
3.2、将 freq 最⼩的 key 删除,那你就得快速得到当前所有 key 最⼩的 freq 是多少。想要时间复杂度O(1) 的话,肯定不能遍历⼀遍去找,那就⽤⼀个变量 minFreq 来记录当前最⼩的 freq 吧。
3.3、可能有多个 key 拥有相同的 freq,所以 freq 对 key 是⼀对多的关系,即⼀个 freq 对应⼀个 key 的列表。
3.4、希望 freq 对应的 key 的列表是存在时序的,便于快速查找并删除最旧的 key。
3.5、希望能够快速删除 key 列表中的任何⼀个 key,因为如果频次为 freq的某个 key 被访问,那么它的频次就会变成 freq+1,就应该从 freq 对应的key 列表中删除,加到 freq+1 对应的 key 的列表中。
其中对于3.2-3.5,可以用key为freq,value为哈希链表的字典来解决。

哈希链表,顾名思义,是链表和哈希集合的结合体。链表不能快速访问链表节点,但是插⼊元素具有时序;哈希集合中的元素⽆序,但是可以对元素进⾏快速的访问和删除。那么,它俩结合起来就兼具了哈希集合和链表的特性,既可以在 O(1) 时间内访问或删除其中的元素,⼜可以保持插⼊的时序。
综上,LFU的实现如下:

# 双向链表
class DoubleList:def __init__(self):self.head = Node(-1, -1) self.tail = Node(-1, -1)self.tail.prev = self.headself.head.next = self.tailself.size = 0def addLast(self, x):x.prev = self.tail.prevself.tail.prev.next = xx.next = self.tailself.tail.prev = xself.size += 1def removeNode(self, x):x.prev.next = x.nextx.next.prev = x.prevself.size -= 1def removeFirst(self):key = self.head.next.keyself.head.next.next.prev = self.headself.head.next = self.head.next.nextself.size -= 1return keyclass Node:def __init__(self, key, value):self.key = keyself.value = valueself.prev = Noneself.next = Noneclass LFUCache:def __init__(self, capacity: int):self.capacity = capacityself.key2freq = {}self.freq2link = collections.defaultdict(DoubleList)self.key2node = {}self.key2value = {}self.freqcount = {}self.minFreq = float("-inf")self.size = 0def get(self, key: int) -> int:# print(key, self.key2freq)if key not in self.key2freq:return -1value = self.key2node[key].value# 更新状态freq = self.key2freq[key]prev_link = self.freq2link[freq]new_link = self.freq2link[freq+1]node = self.key2node[key]prev_link.removeNode(node)# print(freq, prev_link.size)if freq == self.minFreq and prev_link.size == 0:self.minFreq += 1new_link.addLast(node)self.key2freq[key] = freq + 1return valuedef put(self, key: int, value: int) -> None:if self.capacity <= 0:returnif key in self.key2freq:# 存在当前key,更新其value# freq = self.key2freq[key]# 更新状态freq = self.key2freq[key]prev_link = self.freq2link[freq]new_link = self.freq2link[freq+1]node = self.key2node[key]node.value = valueprev_link.removeNode(node)# 当前minFreq为空,增加minFreqif freq == self.minFreq and prev_link.size == 0:self.minFreq += 1new_link.addLast(node)self.key2freq[key] = freq + 1returnif self.size == self.capacity:link = self.freq2link[self.minFreq]deletedKey = link.removeFirst()self.key2freq.pop(deletedKey)self.key2node.pop(deletedKey)self.size -= 1node = Node(key, value)self.key2freq[key] = 1self.key2node[key] = nodeself.freq2link[1].addLast(node)self.minFreq = 1self.size += 1# Your LFUCache object will be instantiated and called as such:
# obj = LFUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)

1332. 删除回文子序列

解法:直接判断
由于字符串本身只含有字母 ‘a’ 和 ‘b’ 两种字符,题目要求每次删除回文子序列(不一定连续)而使得字符串最终为空。题目中只包含两种不同的字符,由于相同的字符组成的子序列一定是回文子序列,因此最多只需要删除 2 次即可删除所有的字符。删除判断如下:

class Solution:def removePalindromeSub(self, s: str) -> int:return 1 if s == s[::-1] else 2

【LeetCode】460 and 1132(LFU缓存机制)相关推荐

  1. lfu算法c语言,LeetCode算法系列 460. LFU 缓存机制

    力扣原题 460. LFU 缓存机制 请你为 最不经常使用(LFU)缓存算法设计并实现数据结构. 实现 LFUCache 类:LFUCache(int capacity) - 用数据结构的容量 cap ...

  2. 高级数据结构与算法 | LFU缓存机制(Least Frequently Used)

    文章目录 LFUCache 结构设计 LFUCache的实现 在之前我写过一篇LRU的博客,如果不了解的建议先看看这篇 高级数据结构与算法 | LRU缓存机制(Least Recently Used) ...

  3. 【LeetCode笔记】146. LRU缓存机制(Java、双向链表、哈希表)

    文章目录 题目描述 思路 & 代码 LinkedHashMap 的写法 题目描述 大名鼎鼎的超高频面试题 太感动,在这道题上花了太多时间了,今天终于补上博客了TvT 思路 & 代码 结 ...

  4. LeetCode 460. LFU缓存(哈希双链表)

    1. 题目 设计并实现最不经常使用(LFU)缓存的数据结构.它应该支持以下操作:get 和 put. get(key) - 如果键存在于缓存中,则获取键的值(总是正数),否则返回 -1. put(ke ...

  5. ​ leetcode 460. LFU 缓存 hard​

    leetcode 460. LFU 缓存  hard 题目描述: 请你为 最不经常使用(LFU)缓存算法设计并实现数据结构. 实现 LFUCache 类: LFUCache(int capacity) ...

  6. 学习笔记 | LeetCode 460. LFU缓存

    LeetCode 460. LFU缓存 请你为 最不经常使用(LFU)缓存算法设计并实现数据结构.它应该支持以下操作:get 和 put. get(key)- 如果键存在于缓存中,则获取键的值(总是正 ...

  7. LeetCode 460. LFU 缓存 -- 哈希查询+双向链表

    LFU 缓存 困难 634 相关企业 请你为 最不经常使用(LFU)缓存算法设计并实现数据结构. 实现 LFUCache 类: LFUCache(int capacity) - 用数据结构的容量 ca ...

  8. LeetCode 460. LFU缓存

    文章目录 题目描述 思路 实现 解法二 扩展 题目描述 实现一个LFU缓存(Least Frequently Used). 在需要移除元素时,移除最近访问频率最低的.可以对每个元素增加一个计数器,访问 ...

  9. LeetCode 146. LRU缓存机制(哈希链表)

    文章目录 1. 题目信息 2. 解题 2.1 手动实现list 2.2 使用内置list 1. 题目信息 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作 ...

最新文章

  1. 清华鲁继文团队提出DynamicViT:一种高效的动态稀疏化Token的ViT
  2. 搭建apache 文档服务器 ubuntu
  3. 思科ssh验证方式_SSH的应用:一个实例两种验证模式的实现
  4. IAR之函数和变量的绝对地址定位
  5. centos7查看当前系统时间、_CentOS7.4.1708查看系统相关信息及系统的初步优化
  6. 给指定的某个commit号加tag并推送
  7. 2019年第十届蓝桥杯国赛B组试题A-平方序列-枚举
  8. sql 2000 安装问题
  9. 读书笔记—《销售铁军》随记3
  10. 深入理解C/C++ [Deep C (and C++)] (1)
  11. 基于RPM包的LAMP搭建
  12. 整理NLPIR基本功能函数
  13. 跟我一起学习ZeroMQ(7):发布订阅模式(Publish-subscribe pattern)ZMQ_XPUB和ZMQ_XSUB
  14. 电线电缆材料stru结构检测知识大全
  15. 《高等数学B(一)》笔记
  16. man fflush
  17. 免费在线证件照制作-超级好用
  18. 新版源支付V5.18三端全套版+去授权/云端监控/免挂
  19. Yolov5 Tensorrt win10 C++ 部署2022
  20. 第三方登陆实践之基于OAuth的FACEBOOK Web Login(最新版)

热门文章

  1. 基于安卓的健康体检预约系统APP
  2. 人生=亲情+爱情+金钱+理想+友情?
  3. 微信小程序 - 搜索历史记录功能(纯前端)
  4. 音乐外链生成php,如何使用php生成短链接网址 第三方API
  5. 零基础python爬虫基础之王者荣耀图片下载(超级简单)
  6. 关于uipath软件安装激活手顺书——在线激活
  7. 免费的云服务器推荐,你会选择哪一款
  8. 判断两个圆相切或相交
  9. 7.1—查找—Sear for a Range
  10. 迅雷协议分析–多链接资源获取