Compare commits

...
3 Commits
Author SHA1 Message Date
wonder b6e6fcf52d 🔄Update: 更新目录 2025-10-06 12:36:57 +08:00
wonder 7d0cd4c50e 🔄Update: LRU 缓存 2025-10-06 11:42:03 +08:00
wonder 8f1f8d55d2 🔄Update: 合并 K 个升序链表 2025-10-06 11:03:21 +08:00
3 changed files with 275 additions and 2 deletions
+2 -2
View File
@@ -48,8 +48,8 @@
- [X] K 个一组翻转链表 - 困难 - [X] K 个一组翻转链表 - 困难
- [X] 随机链表的复制 - 中等 - [X] 随机链表的复制 - 中等
- [X] 排序链表 - 中等 - [X] 排序链表 - 中等
- [ ] 合并 K 个升序链表 - 困难 - [X] 合并 K 个升序链表 - 困难
- [ ] LRU 缓存 - 中等 - [X] LRU 缓存 - 中等
## 二叉树 ## 二叉树
- [ ] 二叉树的中序遍历 - 简单 - [ ] 二叉树的中序遍历 - 简单
+112
View File
@@ -0,0 +1,112 @@
# 合并 K 个升序链表
## 题目
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 1:
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
示例 2:
输入:lists = []
输出:[]
示例 3:
输入:lists = [[]]
输出:[]
提示:
k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i] 按 升序 排列
lists[i].length 的总和不超过 10^4
## 思路
- 分冶
## 代码
```java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
// Special
if (lists == null || lists.length == 0) {
return null;
}
// Init: To List
List<ListNode> nlists = new ArrayList<>(Arrays.asList(lists));
while (nlists.size() > 1) {
// Traverse: l1 + l2 = list
List<ListNode> tempList = new ArrayList<>();
for (int i = 0; i < nlists.size(); i+=2) {
// Get l1, l2
ListNode l1 = nlists.get(i);
ListNode l2 = null;
if (i + 1 < nlists.size()) {
l2 = nlists.get(i + 1);
}
// Merge
tempList.add(mergeTwoLists(l1, l2));
}
nlists = tempList;
}
return nlists.get(0);
}
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
// Init: DummyHead, cur
ListNode dummyHead = new ListNode(-1);
ListNode cur = dummyHead;
// Traverse: Compare
while (list1 != null && list2 != null) {
// val1 = list1.val;
// val2 = list2.val;
ListNode tmp = null;
if (list1.val > list2.val) {
tmp = list2;
list2 = list2.next;
} else {
tmp = list1;
list1 = list1.next;
}
cur.next = tmp;
cur = cur.next;
}
cur.next = list1 == null ? list2 : list1;
return dummyHead.next;
}
}
```
+161
View File
@@ -0,0 +1,161 @@
# LRU 缓存
## 题目
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
函数 get 和 put 必须以 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 * 105 次 get 和 put
## 分析
- 核心数据结构
- ListNode
- prev
- next
- ind
- val
- HashMap<Integer, ListNode>
- ind
- ListNode
- 链表
- head
- tail
- 核心字段
- size
- 当前大小
- cap
- 最大容量
## 代码
```java
class LRUCache {
// Init 1: ListNode
class ListNode {
int key;
int val;
ListNode next;
ListNode prev;
public ListNode () { }
public ListNode (int key, int val) {
this.key = key;
this.val = val;
}
}
ListNode dummyHead = new ListNode(0, 0);
ListNode dummyTail = new ListNode(0, 0);
// Init 2: HashMap
Map<Integer, ListNode> map = new HashMap<>();
// Init 3: Other
private int size;
private int cap;
public LRUCache(int capacity) {
this.cap = capacity;
this.size = 0;
dummyHead.next = dummyTail;
dummyTail.prev = dummyHead;
}
public int get(int key) {
ListNode node = map.get(key);
if (node == null) {
return -1;
}
// Operation: Change Loc
moveToHead(node);
return node.val;
}
public void put(int key, int value) {
ListNode node = map.get(key);
if (node == null) {
ListNode newNode = new ListNode(key, value);
addToHead(newNode);
map.put(key, newNode);
size++;
if (size > cap) {
ListNode tail = removeTail();
map.remove(tail.key);
size--;
}
} else {
node.val = value;
moveToHead(node);
}
}
// Typical Methods
// 1. addToHead
private void addToHead(ListNode node) {
node.next = dummyHead.next;
node.prev = dummyHead;
dummyHead.next.prev = node;
dummyHead.next = node;
}
// 2. removeNode
private void removeNode(ListNode node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
// 3. moveToHead
private void moveToHead(ListNode node) {
removeNode(node);
addToHead(node);
}
// 4. removeTail
private ListNode removeTail() {
ListNode res = dummyTail.prev;
removeNode(res);
return res;
}
}
/**
* 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);
*/
```