劍指offer:n個骰子的點數(java)
阿新 • • 發佈:2019-01-28
題目:把n個骰子仍在地上,所有骰子朝上一面的點數之和為s,輸入n,打印出s的所有可能的值出現的概率。
骰子一共6個面,每個面上都有一個點數,對應的是1-6之間的一個數字。所以n個骰子的點數和的最小值是n,最大值為6n.另外根據排列組合的知識,我們還知道n個骰子的所有點數的排列數為6^n.要解決這個問題,我們需要先統計出每一個點數出現的次數,然後把每一個點數出現的次數除以6^n,就能求出每個點數出現的概率。
解法一:基於遞迴求骰子的點數,時間效率不夠高
現在我們考慮如何統計每一個點數出現的次數。要向求出n個骰子的點數和,可以先把n個骰子分為兩堆:第一堆只有一個,另一個有n-1個。單獨的那一個有可能出現從1到6的點數。我們需要計算從1到6的每一種點數和剩下的n-1個骰子來計算點數和。接下來把剩下的n-1個骰子還是分成兩堆,第一堆只有一個,第二堆有n-2個。我們把上一輪哪個單獨骰子的點數和這一輪單獨骰子的點數相加,再和n-2個骰子來計算點數和。分析到這裡,我們不難發現這是一種遞迴的思路,遞迴結束的條件就是最後只剩下一個骰子。
int g_maxValue = 6; public void printProbability(int number) { if (number < 1) return; int maxSum=number*g_maxValue; int[] pProbabilities= new int[maxSum-number + 1]; Probability(number,pProbabilities); int total=Math.pow((Double)g_maxValue,number); for(int i=number;i<=maxSum;++i){ double ratio = (double) probabilities[flag][i] / total; System.out.println(i); System.out.println(ratio); } delete pProbalities; } public void Probability(int number,int[] pProbabilities); } public void Probability(int original,int current,int sum,int[] pProbabilities){ if(current==1){ pProbabilities[sum-orginal]++; }else{ for(int i=1;i<g_maxValue;++i){ Probability(orginal,current-1,i+sum,pProbabilities); } } }
解法二:基於迴圈求骰子的點數,時間效能好
可以換一個思路來解決這個問題,我們可以考慮用兩個陣列來儲存骰子點數的每一個總數出現的次數。在一次迴圈中,每一個數組中的第n個數字表示骰子和為n出現的次數。在下一輪迴圈中,我們加上一個新的骰子,此時和為n出現的次數。下一輪中,我們加上一個新的骰子,此時和為n的骰子出現的次數應該等於上一次迴圈中骰子點數和為n-1,n-2,n-3,n-4,n-5,n-6的次數之和,所以我們把另一個數組的第n個數字設為前一個數組對應的第n-1,n-2,n-3,n-4,n-5與n-6之和。
public void printProbability(int number) { if (number < 1) return; int g_maxValue = 6; int[][] probabilities = new int[2][]; probabilities[0] = new int[g_maxValue * number + 1]; probabilities[1] = new int[g_maxValue * number + 1]; int flag = 0; for (int i = 1; i <= g_maxValue; i++) probabilities[0][i] = 1; for (int k = 2; k <= number; ++k) { for (int i = 0; i < k; ++i) probabilities[1 - flag][i] = 0; for (int i = k; i <= g_maxValue * k; ++i) { probabilities[1 - flag][i] = 0; for (int j = 1; j <= i && j <= g_maxValue; ++j) probabilities[1 - flag][i] += probabilities[flag][i - j]; } flag = 1 - flag; } double total = Math.pow(g_maxValue, number); for (int i = number; i <= g_maxValue * number; i++) { double ratio = (double) probabilities[flag][i] / total; System.out.println(i); System.out.println(ratio); } }