zoukankan      html  css  js  c++  java
  • 蓄水池算法 抽样统计

    对这个问题我们首先从最简单的例子出发:数据流只有一个数据。我们接收数据,发现数据流结束了,直接返回该数据,该数据返回的概率为1。看来很简单,那么我们试试难一点的情况:假设数据流里有两个数据。

            我们读到了第一个数据,这次我们不能直接返回该数据,因为数据流没有结束。我们继续读取第二个数据,发现数据流结束了。因此我们只要保证以相同 的概率返回第一个或者第二个数据就可以满足题目要求。因此我们生成一个 0 到 1 的随机数R,如果R小于 0.5 我们就返回第一个数据,如果R大于 0.5,返回第二个数据。

            接着我们继续分析有三个数据的数据流的情况。为了方便,我们按顺序给流中的数据命名为1、2、3。我们陆续收到了数据1、2 和前面的例子一样,我们只能保存一个数据,所以必须淘汰 1 和 2 中的一个。应该如何淘汰呢?不妨和上面例子一样,我们按照二分之一的概率淘汰一个,例如我们淘汰了 1. 继续读取流中的数据3,发现数据流结束了,我们知道在长度为 3 的数据流中,如果返回数据 3 的概率为1/3 那么才有可能保证选择的正确性。也就是说,目前我们手里有1,3 两个数据,我们通过一次随机选择,以1/3 的概率留下数据3,以2/3 的概率留下数据 1. 那么数据 1 被最终留下的概率是多少呢?

    • 数据 1 被留下:(1/2)*(2/3) = 1/3
    • 数据 2 被留下概率:(1/2)*(2/3) = 1/3
    • 数据 3 被留下概率:1/3

            这个方法可以满足题目要求,所有数据被留下返回的概率一样!

            因此,我们做一下推论:假设当前正要读取第n个数据,则我们以1/n的概率留下该数据,否则留下前n-1 个数据中的一个。以这种方法选择,所有数据流中数据被选择的概率一样。简短的证明:假设n-1 时候成立,即前n-1 个数据被返回的概率都是1/n-1,当前正在读取第n个数据,以1/n的概率返回它。那么前n-1 个数据中数据被返回的概率为:(1/(n-1))*((n-1)/n)= 1/n,假设成立。

    其伪代码如下:

    Init : a reservoir with the size: k

            for    i= k+1 to N

                M=random(1, i);
                if( M < k)
                     SWAP the Mth value and ith value
           end for

    证明每个数被取到的概率为k/n:

        1. 对于第i个数(i<k),在前k步被选中的概率是1, 从第k+1步开始,i不被选中的概率为k/k+1,那么读到第n个数时, 第i个数(i<k)被选中的概率 = 被选中的概率 * 以后每一步都不被换走的概率,即
          1 * k/k+1 * k+1/k+2 n-1/n = k/n

        2. 对于第j个数(j>=k)被选中的概率为: 在他出现时被选中的概率 * 在他出现以后不被换走的概率,即: 
          k/j * j /j+1 。。。n-1/n = k/n

        3. 综上得证。

  • 相关阅读:
    UVALive 7509 Dome and Steles
    HDU 5884 Sort
    Gym 101194H Great Cells
    HDU 5451 Best Solver
    HDU 5883 The Best Path
    HDU 5875 Function
    卡特兰数
    UVa 11729 Commando War 突击战
    UVa 11292 The Dragon of Loowater 勇者斗恶龙
    Spark Scala Flink版本对应关系
  • 原文地址:https://www.cnblogs.com/hexie/p/4961564.html
Copyright © 2011-2022 走看看