6骰子之和的概率
小夥伴前陣子面試被問到一個問題:
同時擲出六個骰子,求可能出現的點數之和的概率。
思索
6個骰子,點數都是1~6,可能出現的點數和是6~36,那麼各個點數和的概率呢?
從獨立概率入手可能可以更好地解決問題,因爲不需要單獨考慮每個點數和的概率。6個骰子,每個骰子出現1、2、3、4、5、6的概率相等且獨立隨機的,所以總的情況有6^6 種(如果有10個骰子,那就是6^10種)。然後我們對這 6^6 種情況遍歷,然後根據其點數之和丟進其點數和對應的桶裏(需要6~36的31個桶)。最後,每個桶裏的情況個數/6^6即其出現的概率。
這是一種不錯的思路,如果從點數之和入手那很可能陷入很複雜的計算,因爲點數6只有1種,點數7則可能有6種,點數8點數9呢?其複雜度會隨着點數往中間挪而驟增。而且如果骰子不是6顆而是100顆呢?
代碼實現
從思索的結論看,其實我們代碼要做的就只是一個遍歷而已。
那麼,如何遍歷這6^n 種情況?6^n 表示n顆骰子出現的情況,其無非就是第n顆骰子出現的6種情況與n-1顆骰子出現的6^(n-1) 種情況的匹配。所以我們需要考慮遞歸,讓6^n 變成6^(n-1) ... 直到6^0 。
因此,該方法的構建應該是這樣的:
public static void getDiceSum(
int oldSum,
int remainDiceCount,
Map<Integer, Integer> sumMap) {
}
oldSum用於記錄前面骰子的和,remainDiceCount表示還有多少顆骰子沒有加入計算,sumMap用於存儲最後每種和出現的次數。
最終的Java代碼如下:
public static void getDiceSum(
int oldSum,
int remainDiceCount,
Map<Integer, Integer> sumMap) {
if (remainDiceCount == 0)
return;
for (int num = 1; num <= 6; num++) {
if (remainDiceCount == 1) {
int key = oldSum + num;
Integer oldValue = sumMap.get(key);
if (oldValue == null)
oldValue = 0;
sumMap.put(oldSum + num, ++oldValue);
} else {
getDiceSum(oldSum + num, remainDiceCount - 1, sumMap);
}
}
}
實際上,這是一個flatmap的過程,從1個getDiceSum映射到6個getDiceSum,再映射到36個getDiceSum...當remainDiceCount==1的時候說明可以求和了,這時再將當前的這條(6^n 中的一條)的和次數加一丟進sumMap中。