382. 链表随机节点
382. 链表随机节点
🟠 🔖 水塘抽样
链表
数学
随机化
🔗 力扣
LeetCode
题目
Given a singly linked list, return a random node's value from the linked list. Each node must have the same probability of being chosen.
Implement the Solution
class:
Solution(ListNode head)
Initializes the object with the head of the singly-linked listhead
.int getRandom()
Chooses a node randomly from the list and returns its value. All the nodes of the list should be equally likely to be chosen.
Example 1:
Input
["Solution", "getRandom", "getRandom", "getRandom", "getRandom", "getRandom"]
[[[1, 2, 3]], [], [], [], [], []]
Output
[null, 1, 3, 2, 2, 3]
Explanation
Solution solution = new Solution([1, 2, 3]);
solution.getRandom(); // return 1
solution.getRandom(); // return 3
solution.getRandom(); // return 2
solution.getRandom(); // return 2
solution.getRandom(); // return 3
// getRandom() should return either 1, 2, or 3 randomly. Each element should have equal probability of returning.
Constraints:
- The number of nodes in the linked list will be in the range
[1, 10^4]
. -10^4 <= Node.val <= 10^4
- At most
10^4
calls will be made togetRandom
.
Follow up:
- What if the linked list is extremely large and its length is unknown to you?
- Could you solve this efficiently without using extra space?
题目大意
给你一个单链表,随机选择链表的一个节点,并返回相应的节点值。每个节点 被选中的概率一样 。
实现 Solution
类:
Solution(ListNode head)
使用整数数组初始化对象。int getRandom()
从链表中随机选择一个节点并返回该节点的值。链表中所有节点被选中的概率相等。
解题思路
这个问题涉及到水塘抽样算法,目标是从未知长度的链表中随机选择一个节点。水塘抽样算法允许在遍历数据流的过程中,以等概率抽样其中的一个元素。
- 初始化水塘
result
,while 循环遍历链表。 - 从第一个节点开始,以递增的概率选择节点的值:
- 对于第一个节点,以 1/1 的概率选择该节点的值,即
Math.floor(Math.random() * 1) === 0
。 - 对于第二个节点,以 1/2 的概率选择该节点的值,即
Math.floor(Math.random() * 2) === 0
。 - 对于第三个节点,以 1/3 的概率选择该节点的值,即
Math.floor(Math.random() * 3) === 0
。 - 以此类推,对于第 k 个节点,以 1/k 的概率选择该节点的值。
- 对于第一个节点,以 1/1 的概率选择该节点的值,即
- 最终返回水塘中随机选择的节点的值。
这个算法的核心思想是保持水塘 result
中的元素,以相同的概率来替换为新遇到的节点值。这样可以保证每个节点被选中的概率都是 1/n
,其中 n
是节点的序号。最终在整个遍历过程中,所有节点都有相同的被选中的概率。这样实现了在未知长度链表中随机选择节点的目标。
复杂度分析
- 时间复杂度:
O(N + M)
,其中n
是链表的节点数。 - 空间复杂度:
O(1)
。
代码
/**
* @param {ListNode} head
*/
var Solution = function (head) {
this.head = head;
};
/**
* @return {number}
*/
Solution.prototype.getRandom = function () {
let result;
let node = this.head;
let count = 0;
// while 循环遍历链表
while (node) {
count++;
// 生成一个 [0, count) 之间的整数
// 这个整数等于 0 的概率就是 1/count
if (Math.floor(Math.random() * count) == 0) {
result = node.val;
}
node = node.next;
}
return result;
};
相关题目
题号 | 标题 | 题解 | 标签 | 难度 | 力扣 |
---|---|---|---|---|---|
398 | 随机数索引 | 水塘抽样 哈希表 数学 1+ | 🟠 | 🀄️ 🔗 |