題目:已知隨機函數rand(),以p的機率產生0,以1-p的機率產生1,如今要求設計一個新的隨機函數Rand(), 使其以1/n的等機率產生1~n之間的任意一個數算法
一、該問題能夠先生成一個等機率0、1生成器。因爲以p的機率產生0,以1-p的機率產生1,因此00、0一、十、11的生成機率分別是p^二、p(1-p)、p(1-p)和(1-p)^2,咱們發現生成01和10的機率是同樣的,因此咱們能夠標記這兩個序列構造0、1等機率生成器dom
int gen(){ int i1 = rand(); int i2 = rand(); if(i1==0 && i2==1) return 1; else if(i1==1 && i2==0) return 0; else return gen(); return -1; }
二、而後計算n的二進制表示的位數 k = logn + 1;函數
三、填充比特位spa
int Rand(){ int result = 0; for(int i = 0 ; i < k ; ++i){ if(gen() == 1) result |= (1<<i); } if(result > n) return Rand(); return result; }
題目:從數據流中等機率的採樣k個數字設計
先取前k個數字,而後後面的數字以等機率和前面的交換code
證實:
採用概括方法,假設前n個數字等機率的採樣k個數字,那麼每一個數字被採樣的機率爲k/n,如今新來一個數字,變成了n+1個數字,那麼每一個數字被採樣的機率變位k/(n+1),咱們要證實這個 如今假定存在n個數字,來了第n+1個數字,那麼第n+1個數字被選擇的機率是k/(n+1),那麼咱們推算其餘的數字被選擇的機率也是k/(n+1) P(other) = p(other|第n+1個選擇)*p(第n+1個選擇) + p(other|第n+1個不選擇)*p(第n+1個不選擇) = k/n*(1-1/k)*k/(n+1) + k/n*(n+1-k)/(n+1) = k*(k-1) / (n *(n+1) ) + k*(n+1-k) / (n*(n+1)) = k*n/(n *(n+1)) = k/(n+1) 得證。其他數字被選擇的機率依然也是 k/(n+1)
計算機程序設計藝術中提到了這個算法blog
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
證實:it
假設當前是i+1, 按照咱們的規定,i+1這個元素被選中的機率是k/i+1 那麼咱們如今只須要證實前i個元素出現的機率應該也是k/i+1 對這個問題能夠用概括法來證實:k < i <=N 1.當i=k+1的時候,第k+1個元素被選擇的機率明顯爲k/(k+1), 此時前k個元素出現的機率爲 k/(k+1), 結論成立。 2.假設當 j=i 的時候結論成立,此時以 k/i 的機率來選擇第i個元素,前i-1個元素出現的機率都爲k/i。 證實當j=i+1的狀況: 即須要證實當以 k/i+1 的機率來選擇第i+1個元素的時候,此時任一前i個元素出現的機率都爲k/(i+1). 前i個元素出現的機率有2部分組成 ①在第i+1次選擇前得出如今蓄水池中 ②得保證第i+1次選擇的時候不被替換掉 由2知道在第i+1次選擇前,任一前i個元素出現的機率都爲k/i 考慮被替換的機率: 首先要被替換得第 i+1 個元素被選中機率爲 k/i+1,其次是由於隨機替換的池子中k個元素中任意一個,因此被替換的機率是 1/k, 故前i個元素中任一被替換的機率 = k/(i+1) * 1/k = 1/i+1 則沒有被替換的機率爲: 1 - 1/(i+1) = i/i+1 獲得前i個元素出如今蓄水池的機率爲 k/i * i/(i+1) = k/i+1 故證實成立