算法篇-Reservoir Sampling 蓄水池抽样
简介
水库抽样是一系列随机算法,用于从 n 个项目的列表中随机选择k个样本,其中n是一个非常大或未知的数字。通常n足够大,以至于列表不适合主内存。例如,Google 和 Facebook 中的搜索查询列表。所以我们得到了一个大的数字数组(或流),我们需要编写一个有效的函数来随机选择k个数字,其中1 <= k <= n。让输入数组为stream[]。
一个简单的解决方案是创建一个最大大小为k的数组存储库[]。一个一个地从stream[0..n-1]中随机选择一个项目。如果选中的项目之前没有被选中,则将其放入水库[]。要检查一个项目是否先前被选中,我们需要在水库[]中搜索该项目。该算法的时间复杂度为O(k^2)。如果k很大,效率可能会低。此外,如果输入是流的形式,这也不是有效的。
思路
它可以在O(n)时间内解决。该解决方案也非常适合流形式的输入。以下是步骤。
1)创建一个数组reservoir[0..k-1]并将stream[]的前k个项目复制到它。
2)现在一个一个地考虑从第(k+1)个项目到第n个项目的所有项目。
- a)生成一个从 0 到i的随机数,其中i是stream[]中当前项目的索引。令生成的随机数为j。
- b)如果j在 0 到k-1的范围内,则用流[i]替换数组 [j]
证明
- 假设当前是第 M+1 个元素, 它被丢弃的概率是 1/(M+1), 留下的概率就是 M/(M+1). 对于已经在集合中的M个元素, 每个以 1/(M+1) 的概率被丢弃, 留下的概率也是 M/(M+1).
- 假设当前是第 M+2 个元素, 它被丢弃的概率是 2/(M+2), 留下的概率是 M/(M+2). 对于前 M+1 个元素, 它们在集合中的概率是 M/(M+1). 这一次, 它们每个被以1/(M+2)的概率被丢弃, 留下的概率就是 M/(M+1) (M+1)/(M+2) = M/(M+2)
- 依次类推, 到接受第N个元素时, 每个元素被抽取的概率就是M/N
实现
1 |
|
案例
给你一个可能含有 重复元素 的整数数组 nums ,请你随机输出给定的目标数字 target 的索引。你可以假设给定的数字一定存在于数组中。
1 |
|
资料
https://www.geeksforgeeks.org/reservoir-sampling/?ref=gcse
https://leetcode-cn.com/problems/random-pick-index
算法篇-Reservoir Sampling 蓄水池抽样
https://mikeygithub.github.io/2022/04/25/yuque/算法篇-Reservoir Sampling 蓄水池抽样/