美文网首页
LRU、分治、暴力、回溯框架

LRU、分治、暴力、回溯框架

作者: 小小杨树 | 来源:发表于2021-09-29 08:52 被阅读0次

转自:labuladong的算法小抄

⼀、什么是 LRU 算法

就是⼀种缓存淘汰策略。

计算机的缓存容量有限,如果缓存满了就要删除⼀些内容,给新内容腾位置。但问题是,删除哪些内容呢?我们肯定希望删掉哪些没什么⽤的缓存,⽽把有⽤的数据继续留在缓存⾥,⽅便之后继续使⽤。那么,什么样的数据,我们判定为「有⽤的」的数据呢?LRU 缓存淘汰算法就是⼀种常⽤策略。LRU 的全称是 Least RecentlyUsed,也就是说我们认为最近使⽤过的数据应该是是「有⽤的」,很久都没⽤过的数据应该是⽆⽤的,内存满了就优先删那些很久没⽤过的数据。

⼆、LRU 算法描述

LRU 算法实际上是让你设计数据结构:⾸先要接收⼀个 capacity 参数作为缓存的最⼤容量,然后实现两个 API,⼀个是 put(key, val) ⽅法存⼊键值对,另⼀个是 get(key) ⽅法获取 key 对应的 val,如果 key 不存在则返回-1。注意哦,get 和 put ⽅法必须都是 O(1) 的时间复杂度,我们举个具体例⼦来看看 LRU 算法怎么⼯作。


/* 缓存容量为 2 */

LRUCache cache = new LRUCache(2);

// 你可以把 cache 理解成⼀个队列

// 假设左边是队头,右边是队尾

// 最近使⽤的排在队头,久未使⽤的排在队尾

// 圆括号表⽰键值对 (key, val)

cache.put(1, 1);

// cache = [(1, 1)]

cache.put(2, 2);

// cache = [(2, 2), (1, 1)]

cache.get(1); // 返回 1

// cache = [(1, 1), (2, 2)]

// 解释:因为最近访问了键 1,所以提前⾄队头

// 返回键 1 对应的值 1

cache.put(3, 3);

// cache = [(3, 3), (1, 1)]

// 解释:缓存容量已满,需要删除内容空出位置

// 优先删除久未使⽤的数据,也就是队尾的数据

// 然后把新的数据插⼊队头

cache.get(2); // 返回 -1 (未找到)

// cache = [(3, 3), (1, 1)]

// 解释:cache 中不存在键为 2 的数据

cache.put(1, 4);

// cache = [(1, 4), (3, 3)]

// 解释:键 1 已存在,把原始值 1 覆盖为 4

// 不要忘了也要将键值对提前到队头

三、LRU 算法设计

分析上⾯的操作过程,要让 put 和 get ⽅法的时间复杂度为 O(1),我们可以总结出 cache 这个数据结构必要的条件:查找快,插⼊快,删除快,有顺序之分。因为显然 cache 必须有顺序之分,以区分最近使⽤的和久未使⽤的数据;⽽且我们要在 cache 中查找键是否已存在;如果容量满了要删除最后⼀个数据;每次访问还要把数据插⼊到队头。那么,什么数据结构同时符合上述条件呢?哈希表查找快,但是数据⽆固定顺序;链表有顺序之分,插⼊删除快,但是查找慢。所以结合⼀下,形成⼀种新的数据结构:哈希链表。LRU 缓存算法的核⼼数据结构就是哈希链表,双向链表和哈希表的结合体。这个数据结构⻓这样:

image

思想很简单,就是借助哈希表赋予了链表快速查找的特性嘛:可以快速查找某个 key 是否存在缓存(链表)中,同时可以快速删除、添加节点。回想刚才的例⼦,这种数据结构是不是完美解决了 LRU 缓存的需求?也许读者会问,为什么要是双向链表,单链表⾏不⾏?另外,既然哈希表中已经存了 key,为什么链表中还要存键值对呢,只存值不就⾏了?想的时候都是问题,只有做的时候才有答案。这样设计的原因,必须等我们亲⾃实现 LRU 算法之后才能理解,所以我们开始看代码吧〜

分治

实现
1.分解:将原问题分解成一系列子问题

2.解决:递归地求解各个子问题,若子问题足够小,则直接求解

3.合并:将子问题合并成原问题

满足条件
1.原问题与分解成的子问题具有相同的模式

2.原问题分解成的子问题可以独立求解,子问题没有关联性

3.具有分解终止条件,问题足够小时,可以直接求解

4.将子问题合并成原问题,这个合并操作不能复杂度不能太高,否则起不到减少复杂度的效果。

暴力递归

⾸先,这个问题是动态规划问题,因为它具有「最优⼦结构」的。要符合「最优⼦结构」,⼦问题间必互相独⽴。啥叫相互独⽴?你肯定不想看数学证明,我⽤⼀个直观的例⼦来讲解。

⽐如说,你的原问题是考出最⾼的总成绩,那么你的⼦问题就是要把语⽂考到最⾼,数学考到最⾼……为了每门课考到最⾼,你要把每门课相应的选择题分数拿到最⾼,填空题分数拿到最⾼…… 当然,最终就是你每门课都是满分,这就是最⾼的总成绩。

得到了正确的结果:最⾼的总成绩就是总分。因为这个过程符合最优⼦结构,“每门科⽬考到最⾼”这些⼦问题是互相独⽴,互不⼲扰的。

但是,如果加⼀个条件:你的语⽂成绩和数学成绩会互相制约,此消彼⻓。这样的话,显然你能考到的最⾼总成绩就达不到总分了,按刚才那个思路就会得到错误的结果。因为⼦问题并不独⽴,语⽂数学成绩⽆法同时最优,所以最优⼦结构被破坏。

既然知道了这是个动态规划问题,就要思考如何列出正确的状态转移⽅程!

回溯

解决⼀个回溯问题,实际上就是⼀个决策树的遍历过程。你只需要思考 3 个问题:

1、路径:也就是已经做出的选择。

2、选择列表:也就是你当前可以做的选择。

3、结束条件:也就是到达决策树底层,⽆法再做选择的条件。

image

其核⼼就是 for 循环⾥⾯的递归,在递归调⽤之前「做选择」,在递归调⽤之后「撤销选择」

相关文章

  • LRU、分治、暴力、回溯框架

    转自:labuladong的算法小抄 ⼀、什么是 LRU 算法 就是⼀种缓存淘汰策略。 计算机的缓存容量有限,如果...

  • 互联网大厂常考算法及套路深度解析

    常考算法 暴力法 回溯法 分支限界法 分治法 动态规划 贪心法 暴力法 也称枚举法、穷举法、蛮力法。 基本思想: ...

  • 分治、回溯

    分治和回溯本质上都是递归。 分治 Divide & Conquer 在计算机科学中,分治法是建基于多项分支递归的一...

  • 分治,回溯,BFS & DFS,Greedy,二分查找

    分治,回溯 ◉ 多数元素 ◉ 括号生成问题 (使用回溯) ◉ 岛屿数量 ◉ pow ◉ sub...

  • 递归、回溯、分治

    递归 (1)子集 方式一:递归算法 方式二:位运算算法 (2)子集II 方法一:递归算法 方法二:位运算 (3)组...

  • 动态规划

    一、分治,回溯,递归,动态规划 1.1、递归的代码模板 1.2、分治(Divide & Conquer)的代码模板...

  • 8.分治、回溯的实现与特性

    前言 分治与回溯,其实本质上就是递归,只不过它是递归的其中一个细分类。你可以认为分治和回溯最后就是一种特殊的递归,...

  • Algorithm进阶计划 -- 回溯算法

    滑动窗口算法回溯算法框架回溯算法运用 1. 回溯算法框架 回溯算法,是类似枚举的搜索尝试过程,主要是在搜索尝试过程...

  • 算法07-分治、回溯

    《算法练习-文章汇总》[https://www.jianshu.com/p/fc7c0e8cc5cb] 分治:是递...

  • 分治算法和回溯算法

    一、分治算法 核心思想就是分而治之,将原问题划分为n个规模较小的,并且结构与原问题相似的子问题,而后递归地解决这些...

网友评论

      本文标题:LRU、分治、暴力、回溯框架

      本文链接:https://www.haomeiwen.com/subject/mindnltx.html