程序员面试题精选100题(43)-n个骰子的点数[算法]
題目:把n個骰子扔在地上,所有骰子朝上一面的點數之和為S。輸入n,打印出S的所有可能的值出現的概率。
分析:玩過麻將的都知道,骰子一共6個面,每個面上都有一個點數,對應的數字是1到?6之間的一個數字。所以,n個骰子的點數和的最小值為n,最大值為6n。因此,一個直觀的思路就是定義一個長度為6n-n的數組,和為S的點數出現的次數保存到數組第S-n個元素里。另外,我們還知道n個骰子的所有點數的排列數6^n。一旦我們統計出每一點數出現的次數之后,因此只要把每一點數出現的次數除以n^6,就得到了對應的概率。
該思路的關鍵就是統計每一點數出現的次數。要求出n個骰子的點數和,我們可以先把n個骰子分為兩堆:第一堆只有一個,另一個有n-1個。單獨的那一個有可能出現從1到6的點數。我們需要計算從1到6的每一種點數和剩下的n-1個骰子來計算點數和。接下來把剩下的n-1個骰子還是分成兩堆,第一堆只有一個,第二堆有n-2個。我們把上一輪那個單獨骰子的點數和這一輪單獨骰子的點數相加,再和剩下的n-2個骰子來計算點數和。分析到這里,我們不難發現,這是一種遞歸的思路。遞歸結束的條件就是最后只剩下一個骰子了。
基于這種思路,我們可以寫出如下代碼:
int g_maxValue = 6;void PrintSumProbabilityOfDices_1(int number) {if(number < 1)return;int maxSum = number * g_maxValue;int* pProbabilities = new int[maxSum - number + 1];for(int i = number; i <= maxSum; ++i)pProbabilities[i - number] = 0;SumProbabilityOfDices(number, pProbabilities);int total = pow((float)g_maxValue, number);for(int i = number; i <= maxSum; ++i){float ratio = (float)pProbabilities[i - number] / total;printf("%d: %f\n", i, ratio);}delete[] pProbabilities; }void SumProbabilityOfDices(int number, int* pProbabilities) {for(int i = 1; i <= g_maxValue; ++i)SumProbabilityOfDices(number, number, i, 0, pProbabilities); }void SumProbabilityOfDices(int original, int current, int value, int tempSum, int* pProbabilities) {if(current == 1){int sum = value + tempSum;pProbabilities[sum - original]++;}else{for(int i = 1; i <= g_maxValue; ++i){int sum = value + tempSum;SumProbabilityOfDices(original, current - 1, i, sum, pProbabilities);}} }上述算法當number比較小的時候表現很優異。但由于該算法基于遞歸,它有很多計算是重復的,從而導致當number變大時性能讓人不能接受。關于遞歸算法的性能討論,詳見本博客系列的第16題。
我們可以考慮換一種思路來解決這個問題。我們可以考慮用兩個數組來存儲骰子點數每一總數出現的次數。在一次循環中,第一個數組中的第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之和?;谶@個思路,我們可以寫出如下代碼:
??? 值得提出來的是,上述代碼沒有在函數里把一個骰子的最大點數硬編碼(hard code)為6,而是用一個變量g_maxValue來表示。這樣做的好處時,如果某個廠家生產了最大點數為4或者8的骰子,我們只需要在代碼中修改一個地方,擴展起來很方便。如果在面試的時候我們能對面試官提起對程序擴展性的考慮,一定能給面試官留下一個很好的印象。
????????本文已經收錄到《劍指Offer——名企面試官精講典型編程題》一書中,有改動,書中的分析講解更加詳細。歡迎關注。
?????本題已被九度Online Judge系統收錄,歡迎讀者移步到http://ac.jobdu.com/hhtproblems.php在線測試自己的代碼。
??? 博主何海濤對本博客文章享有版權。網絡轉載請注明出處http://zhedahht.blog.163.com/。整理出版物請和作者聯系。
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的程序员面试题精选100题(43)-n个骰子的点数[算法]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 程序员面试题精选100题(40)-扑克牌
- 下一篇: 程序员面试题精选100题(41)-把数组