Python算法题集_LRU 缓存

 Python算法题集_LRU 缓存

  • 题146:LRU 缓存
  • 1. 示例说明
  • 2. 题目解析
    • - 题意分解
    • - 优化思路
    • - 测量工具
  • 3. 代码展开
    • 1) 标准求解【队列+字典】
    • 2) 改进版一【有序字典】
    • 3) 改进版二【双向链表+字典】
  • 4. 最优算法

本文为Python算法题集之一的代码示例

题146:LRU 缓存

1. 示例说明

  • 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。

    实现 LRUCache 类:

    • LRUCache(int capacity)正整数 作为容量 capacity 初始化 LRU 缓存
    • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1
    • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

    函数 getput 必须以 O(1) 的平均时间复杂度运行。

    示例:

    输入
    ["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
    [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
    输出
    [null, null, null, 1, null, -1, null, -1, 3, 4]解释
    LRUCache lRUCache = new LRUCache(2);
    lRUCache.put(1, 1); // 缓存是 {1=1}
    lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
    lRUCache.get(1);    // 返回 1
    lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
    lRUCache.get(2);    // 返回 -1 (未找到)
    lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
    lRUCache.get(1);    // 返回 -1 (未找到)
    lRUCache.get(3);    // 返回 3
    lRUCache.get(4);    // 返回 4
    

    提示:

    • 1 <= capacity <= 3000
    • 0 <= key <= 10000
    • 0 <= value <= 105
    • 最多调用 2 * 105getput

2. 题目解析

- 题意分解

  1. 本题为设计一个整形缓存类,可以指定缓存大小
  2. 基本的设计思路是采用队列控制使用次序,字典进行缓存【哈希】

- 优化思路

  1. 通常优化:减少循环层次

  2. 通常优化:增加分支,减少计算集

  3. 通常优化:采用内置算法来提升计算速度

  4. 分析题目特点,分析最优解

    1. 可以考虑采用有序字典设计缓存类

    2. 可以考虑采用双向链表设计使用队列,缓存还是采用字典


- 测量工具

  • 本地化测试说明:LeetCode网站测试运行时数据波动很大,因此需要本地化测试解决这个问题
  • CheckFuncPerf(本地化函数用时和内存占用测试模块)已上传到CSDN,地址:Python算法题集_检测函数用时和内存占用的模块
  • 本题本地化超时测试用例自己生成,详见【最优算法章节】

3. 代码展开

1) 标准求解【队列+字典】

队列控制使用次序,字典保存键值对

勉强通关,超过05%在这里插入图片描述

import CheckFuncPerf as cfpclass LRUCache_base:
def __init__(self, capacity):self.queue, self.dict, self.capacity, self.queuelen = [], {}, capacity, 0
def get(self, key):if key in self.queue:self.queue.remove(key)self.queue.append(key)return self.dict[key]else:return -1
def put(self, key, value):if key in self.queue:self.queue.remove(key)else:if self.queuelen == self.capacity:self.dict.pop(self.queue.pop(0))else:self.queuelen += 1self.queue.append(key)self.dict[key] = valutmpLRUCache = LRUCache_base(5)
result = cfp.getTimeMemoryStr(testLRUCache, tmpLRUCache, actions)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 运行结果
函数 testLRUCache 的运行时间为 561.12 ms;内存使用量为 4.00 KB 执行结果 = 99

2) 改进版一【有序字典】

采用有序字典【Python3.6之后支持】,同时支持使用顺序和保存键值对

性能卓越,超越93%在这里插入图片描述

import CheckFuncPerf as cfpclass LRUCache_ext1:def __init__(self, capacity):self.data = dict()self.capacity = capacitydef get(self, key):keyval = self.data.get(key, -1)if keyval != -1:self.data.pop(key)self.data[key] = keyvalreturn keyvaldef put(self, key, value)if key in self.data:self.data.pop(key)self.data[key] = valueelse:if len(self.data) < self.capacity:self.data[key] = valueelse:firstpop = next(iter(self.data))self.data.pop(firstpop)self.data[key] = valuetmpLRUCache = LRUCache_ext1(5)
result = cfp.getTimeMemoryStr(testLRUCache, tmpLRUCache, actions)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 运行结果
函数 testLRUCache 的运行时间为 420.10 ms;内存使用量为 0.00 KB 执行结果 = 99

3) 改进版二【双向链表+字典】

采用双向链表维护使用顺序,字典保存键值对,要首先定义双向链表类

性能卓越,超过92%在这里插入图片描述

import CheckFuncPerf as cfpclass ListNodeDouble:def __init__(self, key=None, value=None):self.key = keyself.value = valueself.prev = Noneself.next = None
class LRUCache_ext2:def __init__(self, capacity):self.capacity = capacityself.dict = {}self.head = ListNodeDouble()self.tail = ListNodeDouble()self.head.next = self.tailself.tail.prev = self.headdef move_to_tail(self, key):tmpnode = self.dict[key]tmpnode.prev.next = tmpnode.nexttmpnode.next.prev = tmpnode.prevtmpnode.prev = self.tail.prevtmpnode.next = self.tailself.tail.prev.next = tmpnodeself.tail.prev = tmpnodedef get(self, key: int):if key in self.dict:self.move_to_tail(key)result = self.dict.get(key, -1)if result == -1:return resultelse:return result.valuedef put(self, key, value):if key in self.dict:self.dict[key].value = valueself.move_to_tail(key)else:if len(self.dict) == self.capacity:self.dict.pop(self.head.next.key)self.head.next = self.head.next.nextself.head.next.prev = self.headnewkeyval = ListNodeDouble(key, value)self.dict[key] = newkeyvalnewkeyval.prev = self.tail.prevnewkeyval.next = self.tailself.tail.prev.next = newkeyvalself.tail.prev = newkeyvaltmpLRUCache = LRUCache_ext2(5)
result = cfp.getTimeMemoryStr(testLRUCache, tmpLRUCache, actions)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 运行结果
函数 testLRUCache 的运行时间为 787.18 ms;内存使用量为 0.00 KB 执行结果 = 99

4. 最优算法

根据本地日志分析,最优算法为第2种方式【有序字典】LRUCache_ext1

def testLRUCache(lrucache, actiions):for act in actiions:if len(act) > 1:lrucache.put(act[0], act[1])else:lrucache.get(act[0])return 99
import random
actions = []
iLen = 1000000
for iIdx in range(10):actions.append([iIdx, random.randint(1, 10)])
iturn = 0
for iIdx in range(iLen):if iturn >= 2:actions.append([random.randint(1,10)])else:actions.append([random.randint(1,10), random.randint(1, 1000)])iturn += 1if iturn >= 3:iturn = 0
tmpLRUCache = LRUCache_base(5)
result = cfp.getTimeMemoryStr(testLRUCache, tmpLRUCache, actions)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 算法本地速度实测比较
函数 testLRUCache 的运行时间为 561.12 ms;内存使用量为 4.00 KB 执行结果 = 99
函数 testLRUCache 的运行时间为 420.10 ms;内存使用量为 0.00 KB 执行结果 = 99
函数 testLRUCache 的运行时间为 787.18 ms;内存使用量为 0.00 KB 执行结果 = 99

一日练,一日功,一日不练十日空

may the odds be ever in your favor ~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/468335.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java面试、进阶、实践一网打尽(由电子工业出版社出版)

Java面试、进阶、实践一网打尽 准备好应对Java开发的新挑战吗&#xff1f;我们为您精选了五本核心书籍&#xff0c;一站式满足您在Java面试准备、技能进阶和实战应用的需求。 这套书籍包括《Offer来了&#xff1a;Java面试核心知识点精讲&#xff08;第2版&#xff09;》、《…

电脑数据误删如何恢复?9 个Windows 数据恢复方案

无论您是由于软件或硬件故障、网络犯罪还是意外删除而丢失数据&#xff0c;数据丢失都会带来压力和令人不快。 如今的企业通常将其重要数据存储在云或硬盘上。但在执行其中任何一项操作之前&#xff0c;您很有可能会丢失数据。 数据丢失的主要原因是意外删除&#xff0c;任何…

python算法之 Dijkstra 算法

文章目录 基本思想&#xff1a;步骤&#xff1a;复杂度&#xff1a;注意事项&#xff1a;代码实现K 站中转内最便宜的航班 Dijkstra 算法是一种用于解决单源最短路径问题的经典算法。该问题的目标是找到从图中的一个固定顶点&#xff08;称为源点&#xff09;到图中所有其他顶点…

“从根到叶:深入理解堆数据结构“

一.堆的概念及实现 1.1堆的概念 在数据结构中&#xff0c;堆是一种特殊的树形数据结构。堆可以分为最大堆和最小堆两种类型。 最大堆&#xff1a;对于堆中的任意节点&#xff0c;其父节点的值都不小于它的值。换句话说&#xff0c;最大堆中的根节点是堆中的最大值。并且&…

坚持刷题|重建二叉树

文章目录 题目考察点代码实现实现总结扩展问题从前序和中序遍历中序列构建二叉树题目代码实现与后序实现的异同点 前序和后序可不可以唯一确定一棵二叉树呢&#xff1f; Hello&#xff0c;大家好&#xff0c;我是阿月。坚持刷题&#xff0c;老年痴呆追不上我&#xff0c;今天刷…

2024年危险化学品生产单位安全生产管理人员证考试题库及危险化学品生产单位安全生产管理人员试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年危险化学品生产单位安全生产管理人员证考试题库及危险化学品生产单位安全生产管理人员试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&a…

Solidworks:剖切模型

剖切模型可以看清模型内部。今天设计了一个模型&#xff0c;试验一下如何剖切。 操作很方便&#xff0c;只需要点击一下零件模型上方的剖切按钮&#xff0c;立即就转入剖切视图。剖切后结果如下。 工程图纸中也可以展示剖面视图&#xff0c;操作方法是点击工程图工具页中的“…

Python教程57:海龟画图turtle画动态的流星雨,快让你女朋友看看

---------------turtle源码集合--------------- Python教程91&#xff1a;关于海龟画图&#xff0c;Turtle模块需要学习的知识点 Python教程51&#xff1a;海龟画图turtle画&#xff08;三角形、正方形、五边形、六边形、圆、同心圆、边切圆&#xff0c;五角星&#xff0c;椭…

论文阅读:GamutMLP A Lightweight MLP for Color Loss Recovery

这篇文章是关于色彩恢复的一项工作&#xff0c;发表在 CVPR2023&#xff0c;其中之一的作者是 Michael S. Brown&#xff0c;这个老师是加拿大 York 大学的&#xff0c;也是 ISP 领域的大牛&#xff0c;现在好像也在三星研究院担任兼职&#xff0c;这个老师做了很多这种类似的工…

【从零到Offer】MySQL最左匹配

前言 ​ 相信大家在日常开发时&#xff0c;也经常能听到“最左匹配”这个词&#xff0c;那么什么是最左匹配呢&#xff1f;本篇文章就带你一起探索“最左匹配”的神奇秘密。 什么是最左匹配 ​ 最左匹配&#xff0c;通常指的是最左前缀匹配原则&#xff0c;即MySQL在检索数据…

C++ 特殊类的实现

一、请设计一个类&#xff0c;不能被拷贝 拷贝只会放生在两个场景中&#xff1a;拷贝构造函数以及赋值运算符重载&#xff0c;因此想要让一个类禁止拷贝&#xff0c;只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。 在C98中&#xff1a;将拷贝构造函数与赋值运算符重载…

今天:旧时是这样“破五迎福”

昨&#xff08;正月初四&#xff09;天&#xff0c;笔者——“ 人民体验官 ”&#xff0c; 为了推广人民日报官方微博文化产品所发表在10余个网站自媒体平台上的文章《今天&#xff1a;大年初四迎灶神爷》&#xff0c;不知何故被笔者寄居养老城市的自媒体论坛反复拒之门外&…