【算法题】LFU缓存

本文介绍了LFU(Least Frequently Used)缓存的解题思路,包括Get和Put操作的处理,并讨论了如何进行数据淘汰。提出了通过哈希表和双向链表优化数据结构,以达到O(1)的时间复杂度进行Get操作和优化Put操作时间复杂度。
摘要由CSDN通过智能技术生成

题目:

设计并实现最不经常使用(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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lfu-cache
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

用了当初操作系统课程设计的大概思路实现的LFU,数组存值的方式,不是最优解

  • Get操作: 直接访问存储的map,map中存在对应key的CacheItem则表示缓存命中,则更新访问数据,返回结果
  • Put操作
  1. 判断缓存中是否已存在对应的key,存在则进行访问记录数据、缓存值更新
  2. 新增缓存中未存在的值,则先判断当前缓存容量是否已经满了,如果当前缓存容量满了,则要先通过LFU进行数据淘汰操作。
  3. 插入新的缓存值

淘汰数据方法思路

  1. 遍历先存在的所有缓存
  2. 通过对比每个缓存项的访问时间,以及最后一次访问时间决定淘汰数据的键值
    (1)找出访问次数最少的CacheItem、Cache Key
    (2)如果访问次数最少的缓存键存在多个,则通过每个缓存CacheItem最后访问时间判断哪个是最久没进行访问过的,也就是最后一次访问时间是最早最小的,决定最后淘汰缓存key
  3. 将遍历筛选出来需要淘汰的缓存key,从缓存map中进行delete操作,即删除淘汰缓存

说明下需要更新访问信息的两种情况

  • Get操作,命中缓存 ,需要更新缓存信息
  • Put操作,Put进来的Key对应缓存已存在,则需要进行缓存值以及访问信息的数据更新。

优化大概思路
通过哈希表以及双向链表维护一个插入时间有序的数据结构,因为双向链表中删除、插入一个节点的时间复杂度都是O(1),在进行数据淘汰的时候,可直接删除有序链表中的head或tail Node实现数据淘汰,降低Put操作时间复杂度。

Go解题代码:

type CacheItem struct {
   
	Value int //保存缓存项的值
	VisitTimes int //该缓存访问次数
	VisitTime int //最后一次访问时间
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值