面试高频算法详解-LRU

简介: 面试高频算法详解-LRU

01

题目介绍


题目描述:

leetcode 146 LRU缓存机制中等难度


运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作:获取数据 get 和写入数据 put 。

 

获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。

写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。

 

要求: O(1) 时间复杂度完成这两种操作

 

02

题目分析

 

概念

LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。


重点

1 最近被访问的数据,其优先级最高;

2 优先级低的数据最先被清除;


时间复杂度

O(1)

03

可行方案


1 链表结构

 

使用链表结构保存缓存数据。

  • 每当执行put操作时,遍历链表判断该数据是否为新数据:
  • 若为新数据,则在链表头部新建节点并存放新数据;当链表长度超过缓存大小时,将链表尾部节点删除。
  • 若为旧数据,则说明缓存数据命中,更新该缓存数据,并将命中的链表节点移到链表头部。

 

  • 每当执行get操作时,通过遍历链表进行缓存数据的寻找:
  • 若命中,则根据密钥(key)返回数据值(value),并将数据所在的链表节点置于链表头部;
  • 若未命中,则说明该数据不在缓存中,返回-1。

 

问题:链表在使用的时候,为了确定是否命中,需要对链表结构进行遍历。时间复杂度为o(n),n为链表长度。未满足题目要求。


2 双向链表与哈希表结合


利用双向链表保存缓存数据,利用哈希表解决需要遍历寻找命中的问题。

双向链表中存放的是缓存数据;哈希表中的value值对应于双向链表中的节点地址。


640.jpg



  • 每当执行put操作时,先判断插入的键值对中的key是否存在与哈希表中:
  • 若key已经存在,说明该数据命中缓存,则根据key对应的节点地址找到该缓存数据节点,更新该节点的数据值,并将该节点置于双向链表的头部,同时更新key所对应的节点地址。
  • 若key不存在,说明该数据在缓存中未发生命中,则在双向链表头部创建新的节点存放新的数据,并在哈希表中添加新的key值与链表头部地址相对应。若链表长度大于缓存大小,则删除链表尾部节点以及对应的哈希表中的键值对。

 

  • 每当执行get操作时,先判断插入的的键值对中的key是否存在与哈希表中:
  • 若key已经存在,则可通过key值对应的链表中节点的地址,就可取得缓存数据;同时将该节点置于链表的头部并更新key对应的节点地址。
  • 若对应的key不存在于哈希表中,即未发生命中,返回-1。

04

最终实现


说明


list 是C++ STL中容器,底层实现为双向循环链表,任意位置插入和删除时间复杂度0(1)。

unordered_map 同为C++ STL中容器,底层实现为哈希表。


C++代码:

熟悉其它语言的同学也可看看,理解其中算法思想。


class LRUCache {public:    int size;    list<pair<int, int>> cache;     unordered_map<int, list<pair<int,int>>::iterator> map;        LRUCache(int capacity) {        size = capacity;    }        int get(int key) {        auto it = map.find(key);          if(it == map.end())  //判断key是否存在于哈希表中            return -1;              auto temp = *map[key];          cache.erase(map[key]);  //删除命中节点        cache.push_front(temp);  //在链表头部创建新的数据节点         map[key] = cache.begin();  //更新key所对应的节点地址        return temp.second;             }        void put(int key, int value) {        auto it = map.find(key);        if(it == map.end())        {            if(cache.size()==size)  //若缓存已满            {                auto temp = cache.back();  //获得链表尾部节点                map.erase(temp.first);  //删除尾部节点对应哈希表键值对                cache.pop_back();  //删除尾部节点            }                    cache.push_front(make_pair(key,value));  //在链表头部插入新的数据节点            map[key] = cache.begin();  //更新key值对应的节点地址,指向链表头部        }        else        {                   cache.erase(map[key]);            cache.push_front(make_pair(key,value));            map[key] = cache.begin();        }    }};
/** * Your LRUCache object will be instantiated and called as such: * LRUCache* obj = new LRUCache(capacity); * int param_1 = obj->get(key); * obj->put(key,value); */


评析:

这种方案的实现实际上是最简单的一种LRU思想的表现,但是其利用效率不高。在某些情况下,会导致在重复位置的插入和删除,导致更新效率低下;同时由于哈希表本身的结构也会导致其插入和查询的效率不稳定。不过理解上述的实现能够对数据结构的结合和LRU算法有比较明确的了解。建议充分理解。



相关文章
|
2月前
|
算法 Java 数据库
美团面试:百亿级分片,如何设计基因算法?
40岁老架构师尼恩分享分库分表的基因算法设计,涵盖分片键选择、水平拆分策略及基因法优化查询效率等内容,助力面试者应对大厂技术面试,提高架构设计能力。
美团面试:百亿级分片,如何设计基因算法?
|
2月前
|
算法 前端开发 Java
数据结构与算法学习四:单链表面试题,新浪、腾讯【有难度】、百度面试题
这篇文章总结了单链表的常见面试题,并提供了详细的问题分析、思路分析以及Java代码实现,包括求单链表中有效节点的个数、查找单链表中的倒数第k个节点、单链表的反转以及从尾到头打印单链表等题目。
35 1
数据结构与算法学习四:单链表面试题,新浪、腾讯【有难度】、百度面试题
|
2月前
|
机器学习/深度学习 算法 Java
机器学习、基础算法、python常见面试题必知必答系列大全:(面试问题持续更新)
机器学习、基础算法、python常见面试题必知必答系列大全:(面试问题持续更新)
|
2月前
|
算法 Java 数据库
美团面试:百亿级分片,如何设计基因算法?
40岁老架构师尼恩在读者群中分享了关于分库分表的基因算法设计,旨在帮助大家应对一线互联网企业的面试题。文章详细介绍了分库分表的背景、分片键的设计目标和建议,以及基因法的具体应用和优缺点。通过系统化的梳理,帮助读者提升架构、设计和开发水平,顺利通过面试。
美团面试:百亿级分片,如何设计基因算法?
|
2月前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
85 2
|
3月前
|
机器学习/深度学习 JavaScript 算法
面试中的网红虚拟DOM,你知多少呢?深入解读diff算法
该文章深入探讨了虚拟DOM的概念及其diff算法,解释了虚拟DOM如何最小化实际DOM的更新,以此提升web应用的性能,并详细分析了diff算法的实现机制。
|
4月前
|
消息中间件 存储 算法
这些年背过的面试题——实战算法篇
本文是技术人面试系列实战算法篇,面试中关于实战算法都需要了解哪些内容?一文带你详细了解,欢迎收藏!
|
4月前
|
缓存 算法 前端开发
深入理解缓存淘汰策略:LRU和LFU算法的解析与应用
【8月更文挑战第25天】在计算机科学领域,高效管理资源对于提升系统性能至关重要。内存缓存作为一种加速数据读取的有效方法,其管理策略直接影响整体性能。本文重点介绍两种常用的缓存淘汰算法:LRU(最近最少使用)和LFU(最不经常使用)。LRU算法依据数据最近是否被访问来进行淘汰决策;而LFU算法则根据数据的访问频率做出判断。这两种算法各有特点,适用于不同的应用场景。通过深入分析这两种算法的原理、实现方式及适用场景,本文旨在帮助开发者更好地理解缓存管理机制,从而在实际应用中作出更合理的选择,有效提升系统性能和用户体验。
207 1
|
7天前
|
算法
基于WOA算法的SVDD参数寻优matlab仿真
该程序利用鲸鱼优化算法(WOA)对支持向量数据描述(SVDD)模型的参数进行优化,以提高数据分类的准确性。通过MATLAB2022A实现,展示了不同信噪比(SNR)下模型的分类误差。WOA通过模拟鲸鱼捕食行为,动态调整SVDD参数,如惩罚因子C和核函数参数γ,以寻找最优参数组合,增强模型的鲁棒性和泛化能力。
|
13天前
|
机器学习/深度学习 算法 Serverless
基于WOA-SVM的乳腺癌数据分类识别算法matlab仿真,对比BP神经网络和SVM
本项目利用鲸鱼优化算法(WOA)优化支持向量机(SVM)参数,针对乳腺癌早期诊断问题,通过MATLAB 2022a实现。核心代码包括参数初始化、目标函数计算、位置更新等步骤,并附有详细中文注释及操作视频。实验结果显示,WOA-SVM在提高分类精度和泛化能力方面表现出色,为乳腺癌的早期诊断提供了有效的技术支持。

热门文章

最新文章