蓄水池抽样
Leetcode 398 随机数索引
题目描述
给你一个可能含有 重复元素 的整数数组 nums ,请你随机输出给定的目标数字 target 的索引。你可以假设给定的数字一定存在于数组中。
实现 类:
- Solution(int[] nums) 用数组 nums 初始化对象。
- int pick(int target) 从 nums 中选出一个满足 nums[i] == target 的随机索引 i 。如果存在多个有效的索引,则每个索引的返回概率应当相等。
示例
1 | //输入 |
蓄水池抽样算法
若 nums
并不是在初始化时完全给出,而是持续以「流」的形式给出,且数据流的很长,不便进行预处理的话,我们只能使用蓄水池抽样的方式求解。
对于一般固定大小的数据集合采样,设其样本数量为, 等概率采样个样本,那我们只要通过计算机生成伪随机数就能实现等概率采样。
其间对于每一个样本, 有的概率取或者的概率不取,无论是取了还是没取,都是一锤子的买卖,买定离手。而对于数据流采样,你不知道总共有多少麦穗N,所以来了一个样本你也无从得知应该以具体多大概率保留它或者丢弃它。这时,我们可以求助于巧妙的蓄水池抽样算法。
从算法过程可以看出,对于每一个样本来说,采样不再是一锤子买卖,在整个采样过程完全结束之前,没有人是安全的:即便是某个样本当前被采样选中了,但未来还是有可能会被踢出去,没有免死金牌。
所谓买定不离手,是说手里时刻攥着当前已采样的数据,并在后面不断换入换出。
我们规定当遇到第 个样本,执行一次 的随机操作,当随机结果为0~k时,发生概率为 ,我们将该坐标作为最新的答案候选。
当对每一个样本都进行上述操作后,容易证明每一位下标返回的概率均为 。
对于第个样本,最后被选取的概率为:
代码
1 | class Solution { |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 AFlyingSheep's Blog!
评论