Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions LeetCode/141-150/146. LRU 缓存机制(中等).md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ Tag : 「设计」、「链表」、「哈希表」



运用你所掌握的数据结构,设计和实现一个  `LRU` (最近最少使用) 缓存机制 。
实现 `LRUCache` 类:

运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:

* LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
* int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
* void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
* `LRUCache(int capacity)` 以正整数作为容量 `capacity` 初始化 `LRU` 缓存
* `int get(int key)` 如果关键字 `key` 存在于缓存中,则返回关键字的值,否则返回 $-1$
* `void put(int key, int value)` 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

进阶:你是否可以在 $O(1)$ 时间复杂度内完成这两种操作?

Expand All @@ -38,10 +37,10 @@ lRUCache.get(4); // 返回 4
```

提示:
* 1 <= capacity <= 3000
* 0 <= key <= 3000
* 0 <= value <= $10^4$
* 最多调用 3 * $10^4$ 次 get 和 put
* $1 <= capacity <= 3000$
* $0 <= key <= 3000$
* $0 <= value <= 10^4$
* 最多调用 $3 * 10^4$ 次 `get``put`

---

Expand All @@ -53,7 +52,7 @@ LRU 是一种十分常见的页面置换算法。

**题目让我们实现一个容量固定的 `LRUCache` 。如果插入数据时,发现容器已满时,则先按照 LRU 规则淘汰一个数据,再将新数据插入,其中「插入」和「查询」都算作一次“使用”。**

可以通过 🌰 来理解,假设我们有容量为 $2$ 的 `LRUCache` 和 测试键值对 `[`1-1`,`2-2`,`3-3`]` ,将其按照顺序进行插入 & 查询:
可以通过 🌰 来理解,假设我们有容量为 $2$ 的 `LRUCache` 和 测试键值对 `[1-1,2-2,3-3]` ,将其按照顺序进行插入 & 查询:
* 插入 `1-1`,此时最新的使用数据为 `1-1`
* 插入 `2-2`,此时最新使用数据变为 `2-2`
* 查询 `1-1`,此时最新使用数据为 `1-1`
Expand All @@ -74,15 +73,16 @@ LRU 是一种十分常见的页面置换算法。
具体的,我们使用哈希表来存储「键值对」,键值对的键作为哈希表的 Key,而哈希表的 Value 则使用我们自己封装的 `Node` 类,`Node` 同时作为双向链表的节点。

* 插入:检查当前键值对是否已经存在于哈希表:
* 如果存在,则更新键值对,并将当前键值对所对应的 `Node` 节点调整到链表头部(`refresh` 操作)
* 如果不存在,则检查哈希表容量是否已经达到容量:
* 没达到容量:插入哈希表,并将当前键值对所对应的 `Node` 节点调整到链表头部(`refresh` 操作)
* 已达到容量:先从链表尾部找到待删除元素进行删除(`delete` 操作),然后再插入哈希表,并将当前键值对所对应的 `Node` 节点调整到链表头部(`refresh` 操作)
* 查询:如果没在哈希表中找到该 Key,直接返回 $-1$;如果存在该 Key,则将对应的值返回,并将当前键值对所对应的 `Node` 节点调整到链表头部(`refresh` 操作)

* 如果存在,则更新键值对,并将当前键值对所对应的 `Node` 节点调整到链表头部(`refresh` 操作)

* 如果不存在,则检查哈希表容量是否已经达到容量:
* 没达到容量:插入哈希表,并将当前键值对所对应的 `Node` 节点调整到链表头部(`refresh` 操作)
* 已达到容量:先从链表尾部找到待删除元素进行删除(`delete` 操作),然后再插入哈希表,并将当前键值对所对应的 `Node` 节点调整到链表头部(`refresh` 操作)

一些细节:
* 查询:如果没在哈希表中找到该 Key,直接返回 $-1$;如果存在该 Key,则将对应的值返回,并将当前键值对所对应的 `Node` 节点调整到链表头部(`refresh` 操作)

* 为了减少双向链表左右节点的「判空」操作,我们预先建立两个「哨兵」节点 `head` 和 `tail`。
一些细节: 为了减少双向链表左右节点的「判空」操作,我们预先建立两个「哨兵」节点 `head` 和 `tail`。

代码:
```Java []
Expand Down Expand Up @@ -162,7 +162,7 @@ class LRUCache {

### 最后

这是我们「刷穿 LeetCode」系列文章的第 `No.146` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先将所有不带锁的题目刷完
这是我们「刷穿 LeetCode」系列文章的第 `No.146` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完

在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。

Expand Down