Skip to content
Merged
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions Index/模拟.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
| [318. 最大单词长度乘积](https://leetcode-cn.com/problems/maximum-product-of-word-lengths/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/maximum-product-of-word-lengths/solution/gong-shui-san-xie-jian-dan-wei-yun-suan-cqtxq/) | 中等 | 🤩🤩🤩🤩 |
| [335. 路径交叉](https://leetcode-cn.com/problems/self-crossing/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/self-crossing/solution/gong-shui-san-xie-fen-qing-kuang-tao-lun-zdrb/) | 困难 | 🤩🤩🤩🤩 |
| [345. 反转字符串中的元音字母](https://leetcode-cn.com/problems/reverse-vowels-of-a-string/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/reverse-vowels-of-a-string/solution/gong-shui-san-xie-note-bie-pian-shuang-z-c8ii/) | 简单 | 🤩🤩🤩 |
| [382. 链表随机节点](https://leetcode-cn.com/problems/linked-list-random-node/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/linked-list-random-node/solution/gong-shui-san-xie-xu-shui-chi-chou-yang-1lp9d/) | 中等 | 🤩🤩🤩🤩🤩 |
| [383. 赎金信](https://leetcode-cn.com/problems/ransom-note/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/ransom-note/solution/gong-shui-san-xie-jian-dan-ji-shu-mo-ni-udpzn/) | 简单 | 🤩🤩🤩🤩🤩 |
| [400. 第 N 位数字](https://leetcode-cn.com/problems/nth-digit/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/nth-digit/solution/gong-shui-san-xie-jian-dan-mo-ni-ti-by-a-w5wl/) | 中等 | 🤩🤩🤩🤩 |
| [405. 数字转换为十六进制数](https://leetcode-cn.com/problems/convert-a-number-to-hexadecimal/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/convert-a-number-to-hexadecimal/solution/gong-shui-san-xie-yi-ti-shuang-jie-jin-z-d93o/) | 简单 | 🤩🤩🤩🤩 |
Expand Down
4 changes: 4 additions & 0 deletions Index/蓄水池抽样.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
| 题目 | 题解 | 难度 | 推荐指数 |
| ------------------------------------------------------------ | ------------------------------------------------------------ | ---- | -------- |
| [382. 链表随机节点](https://leetcode-cn.com/problems/linked-list-random-node/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/linked-list-random-node/solution/gong-shui-san-xie-xu-shui-chi-chou-yang-1lp9d/) | 中等 | 🤩🤩🤩🤩🤩 |

1 change: 1 addition & 0 deletions Index/链表.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
| [146. LRU 缓存机制](https://leetcode-cn.com/problems/lru-cache/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/lru-cache/solution/gong-shui-san-xie-she-ji-shu-ju-jie-gou-68hv2/) | 中等 | 🤩🤩🤩🤩🤩 |
| [203. 移除链表元素](https://leetcode-cn.com/problems/remove-linked-list-elements/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/remove-linked-list-elements/solution/gong-shui-san-xie-yi-chu-lian-biao-yuan-ca6fu/) | 简单 | 🤩🤩🤩 |
| [237. 删除链表中的节点](https://leetcode-cn.com/problems/delete-node-in-a-linked-list/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/delete-node-in-a-linked-list/solution/gong-shui-san-xie-jian-dan-lian-biao-mo-rovcb/) | 简单 | 🤩🤩🤩 |
| [382. 链表随机节点](https://leetcode-cn.com/problems/linked-list-random-node/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/linked-list-random-node/solution/gong-shui-san-xie-xu-shui-chi-chou-yang-1lp9d/) | 中等 | 🤩🤩🤩🤩🤩 |
| [430. 扁平化多级双向链表](https://leetcode-cn.com/problems/flatten-a-multilevel-doubly-linked-list/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/flatten-a-multilevel-doubly-linked-list/solution/gong-shui-san-xie-yi-ti-shuang-jie-di-gu-9wfz/) | 中等 | 🤩🤩🤩🤩🤩 |
| [460. LFU 缓存](https://leetcode-cn.com/problems/lfu-cache/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/lfu-cache/solution/gong-shui-san-xie-yun-yong-tong-pai-xu-s-53m3/) | 困难 | 🤩🤩🤩🤩🤩 |
| [725. 分隔链表](https://leetcode-cn.com/problems/split-linked-list-in-parts/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/split-linked-list-in-parts/solution/gong-shui-san-xie-jing-dian-lian-biao-ju-9yj4/) | 简单 | 🤩🤩🤩🤩🤩 |
Expand Down
137 changes: 137 additions & 0 deletions LeetCode/381-390/382. 链表随机节点(中等).md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
### 题目描述

这是 LeetCode 上的 **[382. 链表随机节点](https://leetcode-cn.com/problems/linked-list-random-node/solution/gong-shui-san-xie-xu-shui-chi-chou-yang-1lp9d/)** ,难度为 **中等**。

Tag :「链表」、「模拟」、「蓄水池抽样」



给你一个单链表,随机选择链表的一个节点,并返回相应的节点值。每个节点 **被选中的概率一样** 。

实现 `Solution` 类:
* `Solution(ListNode head)` 使用整数数组初始化对象。
* `int getRandom()` 从链表中随机选择一个节点并返回该节点的值。链表中所有节点被选中的概率相等。

示例:
![](https://assets.leetcode.com/uploads/2021/03/16/getrand-linked-list.jpg)
```
输入
["Solution", "getRandom", "getRandom", "getRandom", "getRandom", "getRandom"]
[[[1, 2, 3]], [], [], [], [], []]

输出
[null, 1, 3, 2, 2, 3]

解释
Solution solution = new Solution([1, 2, 3]);
solution.getRandom(); // 返回 1
solution.getRandom(); // 返回 3
solution.getRandom(); // 返回 2
solution.getRandom(); // 返回 2
solution.getRandom(); // 返回 3
// getRandom() 方法应随机返回 1、2、3中的一个,每个元素被返回的概率相等。
```

提示:
* $链表中的节点数在范围 [1, 10^4] 内$
* $-10^4 <= Node.val <= 10^4$
* 至多调用 `getRandom` 方法 $10^4$ 次


进阶:
* 如果链表非常大且长度未知,该怎么处理?
* 你能否在不使用额外空间的情况下解决此问题?

---

### 模拟

由于链表长度只有 $10^4$,因此可以在初始化时遍历整条链表,将所有的链表值预处理到一个数组内。

在查询时随机一个下标,并将数组中对应下标内容返回出去。

代码:
```Java
class Solution {
List<Integer> list = new ArrayList<>();
Random random = new Random(20220116);
public Solution(ListNode head) {
while (head != null) {
list.add(head.val);
head = head.next;
}
}
public int getRandom() {
int idx = random.nextInt(list.size());
return list.get(idx);
}
}
```
* 时间复杂度:令 $n$ 为链表长度,预处理数组的复杂度为 $O(n)$;随机获取某个值的复杂度为 $O(1)$
* 空间复杂度:$O(n)$

---

### 蓄水池抽样

整理题意:总的样本数量未知,从所有样本中抽取若干个,要求每个样本被抽到的概率相等。

具体做法为:**从前往后处理每个样本,每个样本成为答案的概率为 $\frac{1}{i}$,其中 $i$ 为样本编号(编号从 $1$ 开始),最终可以确保每个样本成为答案的概率均为 $\frac{1}{n}$(其中 $n$ 为样本总数)。**

容易证明该做法的正确性,假设最终成为答案的样本编号为 $k$,那么 $k$ 成为答案的充要条件为「在遍历到 $k$ 时被选中」并且「遍历大于 $k$ 的所有元素时,均没有被选择(没有覆盖 $k$)」。

对应事件概率为:

$$
P = \frac{1}{k} * (1 - \frac{1}{k + 1}) * (1 - \frac{1}{k + 2}) * ... * (1 - \frac{1}{n})
$$

首项 $\frac{1}{k}$ 为选中 $k$ 的概率,后面每项分别为编号为 $[k + 1, n]$ 的样本 **不被选中** 的概率。

化简得:

$$
P = \frac{1}{k} * \frac{k}{k + 1} * \frac{k + 1}{k + 2} * ... * \frac{n - 1}{n}
$$

进一步抵消化简后,可得:
$$
P = \frac{1}{n}
$$

因此,在每一次 `getRandom` 时,从前往后处理每个节点,同时记录当前节点的编号,当处理到节点 $k$ 时,在 $[0, k)$ 范围内进行随机,若随机到结果为 $0$(发生概率为 $\frac{1}{k}$),则将节点 $k$ 的值存入答案,最后一次覆盖答案的节点即为本次抽样结果。

代码:
```Java
class Solution {
ListNode head;
Random random = new Random(20220116);
public Solution(ListNode _head) {
head = _head;
}
public int getRandom() {
int ans = 0, idx = 0;
ListNode t = head;
while (t != null && ++idx >= 0) {
if (random.nextInt(idx) == 0) ans = t.val;
t = t.next;
}
return ans;
}
}
```
* 时间复杂度:令 $n$ 为链表长度,随机获取某个值的复杂度为 $O(n)$
* 空间复杂度:$O(1)$

---

### 最后

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

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

为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。

在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。