我正在解决关于LeetCode的问题,该问题基于储层采样(RS)的概念。问题是:
给定一个数组(可能包含重复项),随机输出给定目标数的索引。目标编号保证存在于数组中。 例如,如果输入为:
{1,2,3,3,3}
且目标为3
,则必须以相同的方式返回任何索引2
,3
和4
可能性。同样,如果目标是1
,则应返回索引0
(显然概率为1
)。
最受欢迎的代码如下:
public class Solution {
int[] nums;
Random rnd;
public Solution(int[] nums) {
this.nums = nums;
this.rnd = new Random();
}
public int pick(int target) {
int result = -1;
int count = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] != target)
continue;
if (rnd.nextInt(++count) == 0)
result = i;
}
return result;
}
}
据我了解RS,我们首先选择n
数字。然后,当我们选择下一个数字时,我们需要以概率1/(n+1)
选择它。怎么做:
rnd.nextInt(++count) == 0
选择概率为1/(n+1)
的数字?我知道我们会++count
进行n+1
,但是分子发生了什么?为什么它是rnd.nextInt()
而不是简单的1
?
修改:问题链接here。
答案 0 :(得分:1)
好的,我们有这句话rnd.nextInt(++count) == 0
我们第一次点击目标时,count
增量为1,语句评估为
rnd.nextInt(1) == 0
总是返回true,因为参数1是独占上限,它可能返回的唯一可能值是0.此时,当前索引被设置为结果,因为我们不知道阵列中是否还有其他目标。
第二次遇到目标时,count
变为2,语句评估为
rnd.nextInt(2) == 0
并且这个返回0或1.因此,索引有50%的机会被选为结果。
因此阵列中有两个已知目标,并且两者都有50%的机会被设置为结果。第二个目标有这个机会是显而易见的,但对于第一个目标,我们可以做一个小的计算。在代码第一次触及if语句时,它有100%的几率被选中,第二次有50%的可能性,第二个目标不成为结果(留下50第一个目标保留的几率为%。这些机会合并了结果
first target as result = 100% x 50% = 50%
这些步骤可以重复超过2个目标,但这使得解释更加复杂。最后,阵列中的所有 N 目标都有 1 / N 成为结果的机会。