几个常见的概率问题

今天研究了下几个简单的概率问题,在这里记录下。

1. 洗牌

问题很简单,有 n 个元素,设计一个能保证随机性的洗牌算法。

直觉想到的算法是:

用一个数组作为新牌堆,不停地从原数组剩下的元素中随机挑一个放入新牌堆,直到原牌堆耗尽。

我们来验证一下它的随机性。考虑一个元素,洗牌后它在第一个位置(即第一次抽牌就选中它)的概率是:

在第二个位置的概率是:

依次类推,可知该元素将被等概率地分配到任意位置,符合要求。

按该思路实现洗牌算法时有两个问题。首先,新牌堆显然需要 的空间;其次,元素从旧数组移入新牌堆后势必会留下空洞,在后续抽牌时要跳过这些空洞位置。

但实际上,新牌堆和旧牌堆元素之和始终为 n,因此整个洗牌过程可以就地完成。我们可以从前向后遍历,对元素 i,前 i-1 个位置构成新牌堆,i 及其后续元素属于旧牌堆。从旧牌堆中随机抽一个元素,与 i 处元素交换,即完成了一次抽牌动作

Alt text

这个算法还有个名字,Fisher–Yates shuffle

代码:

function shuffle(array) {
  var m = array.length, i;

  // While there remain elements to shuffle…
  // 为了方便这里是从后往前遍历的
  while (m) {

    // Pick a remaining element…
    i = Math.floor(Math.random() * m--);

    // And swap it with the current element.
    var t = array[m];
    array[m] = array[i];
    array[i] = t;
  }

}

2. 随机数生成器的转换

听名字有点绕,其实就是给你一个Rand5(),表示随机生成 之间的数字,让你实现一个Rand3()

int Rand3()  
{  
    int x = 5;  
    while(x >= 3) 
        x = Rand5();  
    return x;  
}  

逻辑很简单,用Rand5()不停地产生随机数,直到某个数字落在了 内。最终只会生成 0/1/2 三个数字,看起来似乎每个数字都是等概率的。下面来证明这个结论:

以输出0为例,看看概率是多少。第一次 Rand5 返回 0 的概率是1/5,如果返回3或4(2/5 的概率),则需要调用第二次,同样的,也是1/5的概率得到 0,2/5 的概率得到3或4导致循环继续执行下去,如此反复。因此输出 0 的概率为:

显然这种方法是正确的。

换一下题目,给一个Rand(3),怎么生成一个Rand(5)呢?由于 可以构造出Rand(9),对它再应用上述算法即可。

解释下 为什么可以得到Rand(9) 得到一个随机数集合0,3,6 得到0,1,2,二者相加的结果刚好均匀地分布在 区间内。推广这个结论可得, 可以得到 区间内的随机数生成器。

3. 蓄水池抽样

蓄水池抽样是要解决这样一个问题:给定一个很大的集合,集合总数 n 不能确定,只能遍历一遍,要求从中随机选取 k 个元素。

蓄水池算法的原理是:维护一个大小为 k 的蓄水池,用集合的前 k 个元素初始化之;对后续每个元素 i,都以 的概率替换掉蓄水池中的某个元素。

代码:

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  

下面来证明一下该算法的正确性。

对某个元素,第一次就选中它的概率是 ,第二次才选中它的概率是 ,第三次第四次也类似,这跟之前的洗牌场景很像。因此,最终该元素被选中的概率就等于

  1. 当 n == k 时,每个元素出现在蓄水池的概率都是1,即
  2. 当 n == k+1 时,第一次考察发生在元素 k+1 处,根据算法,它被放入蓄水池的概率为 ;对原蓄水池中的任一元素,该次考察后被换出去的概率等于:

    所以,元素依然在蓄水池内的概率为

  3. 当 n == k+2 时,根据2,前 k+1 内的元素在第二次考察(即考察第 k+2 个元素)前在蓄水池内的概率为

    同样的,第 k+2 个元素被放入蓄水池的概率为

    对前 k+1 的元素,在第二次考察后在蓄水池要求 1)之前就在蓄水池;2)这次没有被交换出去:

    也符合条件。

  4. 推广上述过程即可得证。

4. 参考

  1. Fisher–Yates Shuffle
  2. 利用等概率Rand5产生等概率Rand3
  3. 海量数据随机抽样问题(蓄水池问题)
Loading Disqus comments...
目录