如何在这里使用水库采样?

时间:2017-08-18 16:58:07

标签: java

我正在解决关于LeetCode的问题,该问题基于储层采样(RS)的概念。问题是:

  

给定一个数组(可能包含重复项),随机输出给定目标数的索引。目标编号保证存在于数组中。   例如,如果输入为:{1,2,3,3,3}且目标为3,则必须以相同的方式返回任何索引234可能性。同样,如果目标是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

1 个答案:

答案 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 成为结果的机会。