简述
水塘抽样是一系列的随机算法,其目的在于从包含n个项目的集合S中选取k个样本,其中n为一很大或未知的数量,尤其适用于不能把所有n个项目都存放到内存的情况。
时间复杂度:O(n)
空间复杂度:O(1)
题目列表
链表随机节点
给你一个单链表,随机选择链表的一个节点,并返回相应的节点值。每个节点 被选中的概率一样 。
实现 Solution 类:
Solution(ListNode head) 使用整数数组初始化对象。
int getRandom()从链表中随机选择一个节点并返回该节点的值。链表中所有节点被选中的概率相等。
- 解题思路:
题目解析:
链表 = 样本数未知
随机 + 未知 👉 水塘抽样
对第i个节点有:
替换答案的概率是:1/i
证明:
第i个选中的概率=选i后面不中
1/i * 1-(1/i+1) …… = 1/n (n为样本数)
- 实现代码:
class Solution:
def __init__(self, head: Optional[ListNode]):
self.head = head
def getRandom(self) -> int:
node, i, ans = self.head, 1, 0
while node:
if randrange(i) == 0: # 1/i 的概率选中(替换为答案)
ans = node.val
i += 1
node = node.next
return ans
- 细节:
random.randrange ([start,] stop [,step])
返回 start到stop之间的随机数
步长为step
randrange(100, 1000, 2) : 976
randrange(100, 1000, 3) : 520
随机数索引
给定一个可能含有重复元素的整数数组,要求随机输出给定的数字的索引。 您可以假设给定的数字一定存在于数组中。
注意:
数组大小可能非常大。 使用太多额外空间的解决方案将不会通过测试。
- 解题思路:
转化为重复元素中的抽样即可
- 实现代码:
class Solution:
def __init__(self, nums: List[int]):
self.n = nums
def pick(self, target: int) -> int:
for i in range((cnt:=0) or len(self.n)):if self.n[i]==target and randrange(cnt:=cnt+1)==0:ans=i
return ans
- 细节:
利用海象运算符进行代码简化