1 | # Python常用内置随机函数 |
1 | # random产生[0,1)之间的浮点数 |
蓄水池抽样算法
原理
- 问题:给定一个长度为n的数组,从中随机抽取k个元素。要求每个元素被选取的概率相等,且时间复杂度为O(n)。
- 思路:维护一个长度为k的蓄水池,首先将前k个元素放入蓄水池,然后从第k+1个元素开始向后遍历,遍历到第i个元素时,以k/i的概率选中第i个元素,随机替换掉蓄水池中任一元素,直至遍历完成,蓄水池中的k个元素就是最终抽样结果。
证明:蓄水池抽样算法使得每个元素被抽到的概率均为k/n。我们只需要证明遍历完第i个元素时,前i个元素中每个元素被抽取到概率均为k/i:
- 当i=k时,前i个元素每个被抽取到的概率为$1=\frac{k}{i}$
- 假设遍历完第i个元素后,前i个元素每个元素被抽取到的概率为$\frac{k}{i}$,现在考虑第i+1个元素,以$\frac{k}{i+1}$的概率选中第i+1个元素,替换蓄水池中随机一个元素x:
- 对于第i+1个元素来说,放入蓄水池的概率为$\frac{k}{i+1}$
- 对于前i个元素来说,遍历第i+1个元素前,每个元素在蓄水池中的概率为$\frac{k}{i}$,遍历完第i+1个元素后仍在蓄水池中的概率为:$\frac{k}{i}\cdot (1-\frac{k}{i+1}\cdot \frac{1}{k})=\frac{k}{i+1}$
- 当i=n时,前n个元素被抽取到的概率均为$\frac{k}{n}$
实现:
1 | import random |
例题
LeetCode[398] 随机抽样
- 问题:给定一个可能含有重复元素的整数数组,要求随机输出给定的数字的索引。 您可以假设给定的数字一定存在于数组中
- 思路:只对等于给定数字的元素计数
- 代码:
1 | import random |
[LeetCode 528] 按权重随机抽样
- 问题:
1 | 给定一个正整数数组 w ,其中 w[i] 代表位置 i 的权重,请写一个函数 pickIndex ,它可以随机地获取位置 i,选取位置 i 的概率与 w[i] 成正比。 |
- 思路:
1 | 思路: |
- 代码:
1 | import random |