【算法】如何用隨機函數rand5來構造隨機函數rand7

常規方法

  • 今天公司有一個面試題是這樣的:假如有一個函數rand5能等概率生成1 - 5 之間的整數,如何利用rand5來實現rand7?rand7函數的要求是能夠等概率生成1 - 7之間的整數。說實話我自己也不是很清楚。
  • 這個問題很經典的。carreercup那本書上有個常見的解法,我記得算法大概是這樣的,用PHP寫寫吧:
01 echo 'rand7 = '.rand7();
02  
03 function rand7()
04 {
05     while (true)
06     {
07         //得出[0,24]的平均分佈
08         $i = 5 * (rand5() - 1) + (rand5() - 1);
09         //只取前21個, 前21個也是平均分佈,然後mod 7
10         if$i < 21 )
11         {
12             return $i % 7 + 1;
13         }
14     }
15 }
  • 這麼寫是什麼意思呢?
  • 兩次使用rand5(),可以生成1-25的所有數。5 * (rand5() - 1) 可以生成 0 - 20,而後面的則可以生成0 - 4。用數學表達的話就是 [0, 24]。
  • [0, 24] 範圍內生成的隨機數$i如果大於21,就用 while (true) 重新生成。當$i < 21的時候,就可以用模運算了。
  • 明白了。當 $i < 21的時候,模 7 的結果是 0-6,加1就可以修正爲 1-7,這樣就可以通過rand5來實現rand7了。

算法的一些釋疑

  • 話說得出[0,24]的平均分佈的 $i = 5 * (rand5() - 1) + (rand5() - 1); 爲什麼要這麼寫呢?爲什麼不能直接 $i = 6 * (rand5() - 1) ?
  • rand5()產生的是[1,5]的均勻分佈,但是有沒有發現最後產生的rand7()卻是[0,6]的,那麼平均分佈是如何實現的呢?
  • 5*(rand5()-1) 生成的是 0, 5,10,15,20各20%的概率,rand5()-1 是0,1,2,3,4各20%概率,兩者相加,就是0-24各1/25的概率,這樣就保證了平均分佈的問題了。基本的概率和排列組合問題了。
  • 前21個也是平均分佈,那麼我取 $i < 14 也可以麼?這樣也能保證平均分佈嗎?
  • 應該也可以,但是增加了可能的循環次數。你看到 while (true) 這行代碼嗎?當while裏面的條件不滿足,循環就會一直下去。所以從程序上考慮,就是用了21而非14吧。

晚些時候

  • 我Google了下,貌似還有其它思路。先用2個rand5產生rand10(注意,不是相加),然後從rand10產生rand7。
01 // Gen 0, 1 equal probability
02 int rand01()
03 {
04     int i = rand5();
05     while (i > 4) {i = rand5();}
06     return i % 2;
07 }
08   
09 // Gen 0, 1, 2, 3, 4, 5, 6, 7 equal probability
10 int rand07()
11 {
12     return rand01() << 2 + rand01() << 1 + rand01();
13 }
14   
15 // Gen 1, 2, 3, 4, 5, 6, 7 equal probability
16 int rand7()
17 {
18     int i = rand07();
19     while (i == 0) {i = rand07();}
20     return i;
21 }
  • 還有一種方法,可以直接把概率問題轉化到矩陣中解決。
01 int matrix[5][5];
02   
03 memset(matrix, 0, sizeof(matrix));
04   
05 // Set matrix with num 1-7, each num has the same count.
06 for (int i = 1; i <= 7; ++i)
07 {
08     for (int j = 0; j < 3; ++j)
09     {
10         *matrix++ = i;
11     }
12 }
13   
14 int rand7()
15 {
16     int i;
17   
18     do
19     {
20         i = matrix[rand5() - 1][rand5() - 1];
21     while (i == 0);
22   
23     return i;
24 }
  • 你還真好學。。

通過這個面試題學到了等概率問題的各種解法,可以從把數從二進制角度看,可以用公式拼接出更大的等概率值域空間,也可以直接把概率問題轉化到矩陣中解決。

rand5() 它能夠等概率生成 1-5 之間的整數。所謂等概率就是1,2,3,4,5 生產的概率均爲 0.2 。現在利用rand5(), 構造一個能夠等概率生成 1- 7 的方法。 這裏有兩個特別重要的點,一是 如果 rand5() + rand5(), 我們能夠產生一個均勻分佈的 1 - 10 嗎? 答案是否定的。比如對於 6來講(4+2, 2+4, 3+3),它被生成的生成的概率比1 (1+0,0+1)要大。

第二個點就是我們不可能用rand5()直接產生 1- 7 的數,不管你用加減乘除都不行。所以,我們要構造一個更大的範圍,使得範圍裏每一個值被生成的概率是一樣的,而且這個範圍是7的倍數。

先產生一個均勻分佈的 0, 5, 10, 15, 20的數,再產生一個均勻分佈的 0, 1, 2, 3, 4 的數。相加以後,會產生一個 0到24的數,而且每個數(除0外)生成的概率是一樣的。我們只取 1 - 21 這一段,和7 取餘以後+1就能得到完全均勻分佈的1-7的隨機數

發佈了185 篇原創文章 · 獲贊 19 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章