zoukankan      html  css  js  c++  java
  • 从n个数中随机选取m个

    咋一看,这是个很简单的问题,但是如果n是个不确定的数呢?比如服务器每天会收到数以亿计的请求,但是目前服务器端不希望保存所有的请求,只想随机保存这些请求中的m个。试设计一种算法,能够使服务器实时保存m个请求,并使这些请求是从所有请求中的大致等概率被选中的结果。注意:不到一天的结束,是不能提前知道当天所有请求数n是多少的。下面我们分两种情况讨论(1)n已知,(2)n未知。

    1 n已知

    可以将问题简化为:从集合A(a_1, a_2, … ,a_n),中随机选取m(0≤m≤n)个元素,使得每个数被选取的概率相等。可以很简单的计算每个数被选取的概率是m/n如果集合A里面的元素本来就具有随机性, 每个元素在各个位置上出现的概率相等, 并且只在A上选取一次数据,那么直接返回A的前面m个元素就可以了, 或者可以采取每隔k个元素取一个等类似的方法。这样的算法局限很大, 对集合A的要求很高。

    假设集合A中的元素在各个位置上不具有随机性, 比如已经按某种方式排序了,那么我们可以遍历集合A中的每一个元素a_i,根据一定的概率选取a_i,这个概率是多少呢,设m’为还需要从A中选取的元素个数, n’为元素a_i及其右边的元素个数, 也即n’=(n-i+1)。那么选取元素a_i的概率为 m’/n’。这个证明较复杂,下面简单验证一下前两个元素被选中的概率:(设p(a_i=1)表示a_i被选中的概率,p(a_i=0)表示a_i没有被选中的概率)

    (1)很显然 p(a_1=1)=m/n

    (2)p(a_2=1)= p(a_2=1,a_1=1)+p(a_2=1,a_1=0)
    = p(a_1=1)*p(a_2=1│a_1=1)+ p(a_1=0)* p(a_2=1│a_1=0)
    = m/n * (m-1)/(n-1) + (n-m)/n*m/(n-1)
    = m/n

    实际编程中选取某个元素时,可以生成一个[0,1]之间的随机数k, 若k<=m'/n'则选取这个元素,否则抛弃。

    2 n未知

    这个问题可以简化为:一个整数序列生成器,以一定时间间隔生成一个新的整数,一天之内会生成N个,希望实时保存m个整数,使得任何时刻这m个整数都是当前已生成的所有整数数量n中等概率抽取的结果,即概率均为m/n。由于n是未知的,我们需要以某种特殊的方式进行判决保存还是不保存,以使得满足概率要求。具体步骤如下:

    (1)对于前m个请求直接保存到服务器上,对应整数序列相当于,整数数组的前m个直接存下来。

    (2)对于m个以后的第k个新请求,以m/k的概率选择保存,并同从已保存的m个请求中随机选出的一个进行交换。

    细说就是,

      • 对于第m+1个请求,以m/(m+1)的概率选择留下,如果留下了则从已保存的m个请求中随机选出一个,同它交换;
      • 对于第m+2个请求,以m/(m+2)的概率选择留下,如果留下了则从已保存的m个请求中随机选出一个,同它交换;
      • 对于第m+3个请求,以m/(m+3)的概率选择留下,如果留下了则从已保存的m个请求中随机选出一个,同它交换;

                …

    下面我们用数学归纳法证明这个方法使每个元素被选取的概率是m/n:

    (1)当n=m+1时,
    对于第m+1个请求以概率m/(m+1)选择留下,显然满足m/n的要求;
    对于前m个请求中的任何一个,能被选择留下有两种情况:a.第m+1个请求被选择留下了并且没有和自己进行交换; b.第m+1个请求没有被选择留下来而自己确实已被选择留下来了。
    所以,概率计算为 m/(m+1) * (m-1)/m + (1 – m/(m+1)) * 1 = (m-1)/(m+1) + 1/(m+1) = m/(m+1)

    (2)假设当n=N时,仍然正确,即任何一个请求被选中的概率都是m/N,现在推到证明当n=N+1时,任何一个请求被选中留下的概率是m/(N+1)。
    对于第N+1个请求,因为是以m/n=m/(N+1)的概率选中的,所以显然满足要求;
    对于前m个请求中任何一个,能被选中留下同样分为同上的两种情况:a.一种是第N+1个被选中了但随机抽取出与它交换的不是自己;  b.另一种情况是自己已留下并且第N+1个未被选中留下。并且前m个请求中的某个被选中的前提是:在处理完第N个请求后,该请求被选中,根据假设这个概率是m/N。

    和概率为: [ m/(N+1) * (m-1)/m + (1-m/(N+1)) ]* m/N = [ (m-1)/(N+1) + (N+1-m)/(N+1) ] * m/N = m/(N+1)。

    即当n=N+1时,仍然正确。

    综合1)、2)可知,此方法满足等概率要求

    当然这种选取方法也适用于n已知的情况。

     【版权声明】转载请注明出处 http://www.cnblogs.com/TenosDoIt/p/3364139.html

  • 相关阅读:
    网络流24题(03)最小路径覆盖问题(二分图匹配 + 最大流)
    POJ 1161 Help Jimmy(逆向思维的DP + 记忆化搜索总结)
    UVa 11248 Frequency Hopping(最小割入门)
    HDOJ 2767 Proving Equivalences(强连通算法入门)
    POJ 1336 The KLeague(最大流)
    POJ 1459 Power Network(最大流入门)
    ZOJ 1679 Telescope(区间DP变型题)
    网络流24题(02)太空飞行计划(最大流最小割)
    POJ 1160 Post Office(抽象的二维DP)
    网络流24题(01)搭配飞行员(最大流)
  • 原文地址:https://www.cnblogs.com/TenosDoIt/p/3364139.html
Copyright © 2011-2022 走看看