Compare commits
6
Commits
474ff68c82
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44b68083eb | ||
|
|
66a49a59b1 | ||
|
|
85ea486fd2 | ||
|
|
b6e6fcf52d | ||
|
|
7d0cd4c50e | ||
|
|
8f1f8d55d2 |
@@ -48,8 +48,8 @@
|
||||
- [X] K 个一组翻转链表 - 困难
|
||||
- [X] 随机链表的复制 - 中等
|
||||
- [X] 排序链表 - 中等
|
||||
- [ ] 合并 K 个升序链表 - 困难
|
||||
- [ ] LRU 缓存 - 中等
|
||||
- [X] 合并 K 个升序链表 - 困难
|
||||
- [X] LRU 缓存 - 中等
|
||||
|
||||
## 二叉树
|
||||
- [ ] 二叉树的中序遍历 - 简单
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
# 二叉树的中序遍历
|
||||
|
||||
## 题目
|
||||
给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。
|
||||
|
||||
|
||||
|
||||
示例 1:
|
||||
|
||||
|
||||
输入:root = [1,null,2,3]
|
||||
输出:[1,3,2]
|
||||
示例 2:
|
||||
|
||||
输入:root = []
|
||||
输出:[]
|
||||
示例 3:
|
||||
|
||||
输入:root = [1]
|
||||
输出:[1]
|
||||
|
||||
|
||||
提示:
|
||||
|
||||
树中节点数目在范围 [0, 100] 内
|
||||
-100 <= Node.val <= 100
|
||||
|
||||
|
||||
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
|
||||
|
||||
## 思路
|
||||
|
||||
- 递归
|
||||
- 迭代
|
||||
|
||||
## 代码
|
||||
|
||||
- 递归
|
||||
|
||||
```java
|
||||
/**
|
||||
* Definition for a binary tree node.
|
||||
* public class TreeNode {
|
||||
* int val;
|
||||
* TreeNode left;
|
||||
* TreeNode right;
|
||||
* TreeNode() {}
|
||||
* TreeNode(int val) { this.val = val; }
|
||||
* TreeNode(int val, TreeNode left, TreeNode right) {
|
||||
* this.val = val;
|
||||
* this.left = left;
|
||||
* this.right = right;
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
class Solution {
|
||||
public List<Integer> inorderTraversal(TreeNode root) {
|
||||
// Init: Res
|
||||
List<Integer> res = new ArrayList<>();
|
||||
inorder(root, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
public void inorder(TreeNode root, List<Integer> res) {
|
||||
if (root == null) {
|
||||
return;
|
||||
}
|
||||
inorder(root.left, res);
|
||||
res.add(root.val);
|
||||
inorder(root.right, res);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- 迭代
|
||||
|
||||
```java
|
||||
/**
|
||||
* Definition for a binary tree node.
|
||||
* public class TreeNode {
|
||||
* int val;
|
||||
* TreeNode left;
|
||||
* TreeNode right;
|
||||
* TreeNode() {}
|
||||
* TreeNode(int val) { this.val = val; }
|
||||
* TreeNode(int val, TreeNode left, TreeNode right) {
|
||||
* this.val = val;
|
||||
* this.left = left;
|
||||
* this.right = right;
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
class Solution {
|
||||
public List<Integer> inorderTraversal(TreeNode root) {
|
||||
// Init: stack, res
|
||||
Deque<TreeNode> stack = new LinkedList<>();
|
||||
List<Integer> res = new ArrayList<>();
|
||||
TreeNode cur = root;
|
||||
// Traverse 1: Judge
|
||||
while (cur != null || stack.size() > 0) {
|
||||
// Traverse 2: Add
|
||||
while (cur != null) {
|
||||
stack.push(cur);
|
||||
cur = cur.left;
|
||||
}
|
||||
cur = stack.peek();
|
||||
stack.pop();
|
||||
res.add(cur.val);
|
||||
cur = cur.right;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,66 @@
|
||||
# 二叉树的最大深度
|
||||
|
||||
## 题目
|
||||
|
||||
给定一个二叉树 root ,返回其最大深度。
|
||||
|
||||
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
|
||||
|
||||
|
||||
|
||||
示例 1:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
输入:root = [3,9,20,null,null,15,7]
|
||||
输出:3
|
||||
示例 2:
|
||||
|
||||
输入:root = [1,null,2]
|
||||
输出:2
|
||||
|
||||
|
||||
提示:
|
||||
|
||||
树中节点的数量在 [0, 104] 区间内。
|
||||
-100 <= Node.val <= 100
|
||||
|
||||
## 思路
|
||||
|
||||
- 递归
|
||||
|
||||
## 代码
|
||||
|
||||
- 递归
|
||||
|
||||
```java
|
||||
/**
|
||||
* Definition for a binary tree node.
|
||||
* public class TreeNode {
|
||||
* int val;
|
||||
* TreeNode left;
|
||||
* TreeNode right;
|
||||
* TreeNode() {}
|
||||
* TreeNode(int val) { this.val = val; }
|
||||
* TreeNode(int val, TreeNode left, TreeNode right) {
|
||||
* this.val = val;
|
||||
* this.left = left;
|
||||
* this.right = right;
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
class Solution {
|
||||
public int maxDepth(TreeNode root) {
|
||||
// Init: cur
|
||||
TreeNode cur = root;
|
||||
// Special
|
||||
if (root == null) {
|
||||
return 0;
|
||||
}
|
||||
// Recursion
|
||||
return Math.max(maxDepth(cur.left), maxDepth(cur.right)) + 1;
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,70 @@
|
||||
# 翻转二叉树
|
||||
|
||||
## 题目
|
||||
|
||||
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
|
||||
|
||||
|
||||
|
||||
示例 1:
|
||||
|
||||
|
||||
|
||||
输入:root = [4,2,7,1,3,6,9]
|
||||
输出:[4,7,2,9,6,3,1]
|
||||
示例 2:
|
||||
|
||||
|
||||
|
||||
输入:root = [2,1,3]
|
||||
输出:[2,3,1]
|
||||
示例 3:
|
||||
|
||||
输入:root = []
|
||||
输出:[]
|
||||
|
||||
|
||||
提示:
|
||||
|
||||
树中节点数目范围在 [0, 100] 内
|
||||
-100 <= Node.val <= 100
|
||||
|
||||
## 思路
|
||||
|
||||
- 递归
|
||||
- 对于每一个节点
|
||||
- 为空
|
||||
- 返回当前节点 null
|
||||
- 不为空
|
||||
- 交换左右节点,再返回当前节点
|
||||
|
||||
## 代码
|
||||
|
||||
```java
|
||||
/**
|
||||
* Definition for a binary tree node.
|
||||
* public class TreeNode {
|
||||
* int val;
|
||||
* TreeNode left;
|
||||
* TreeNode right;
|
||||
* TreeNode() {}
|
||||
* TreeNode(int val) { this.val = val; }
|
||||
* TreeNode(int val, TreeNode left, TreeNode right) {
|
||||
* this.val = val;
|
||||
* this.left = left;
|
||||
* this.right = right;
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
class Solution {
|
||||
public TreeNode invertTree(TreeNode root) {
|
||||
// Special
|
||||
if (root == null) return null;
|
||||
TreeNode left = invertTree(root.left);
|
||||
TreeNode right = invertTree(root.right);
|
||||
root.left = right;
|
||||
root.right = left;
|
||||
return root;
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -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);
|
||||
*/
|
||||
```
|
||||
Reference in New Issue
Block a user