《劍指offer》 面試題43 n個骰子的點數 (java)

來源:互聯網
上載者:User

標籤:代碼量   new   使用   --   div   int   源碼   時間   ble   

引言:寫這篇文章的初衷只是想做個筆記,因為這道題代碼量有點大,有點抽象,而書上並沒有詳細的注釋。為了加深印象和便於下次複習,做個記錄。

原題:把n個骰子扔到地上,所有骰子朝上一面的點數之後為s. 輸入n,列印出s所有可能的值出現的機率。(每個骰子6個面,點數從1到6)

解法一:基於遞迴,時間效率不高

遞迴的思想一般是分而治之,把n個骰子分為第一個和剩下的n-1個。先計算第一個骰子每個點數出現的次數,再計算剩餘n-1個骰子出現的點數之和。求n-1個骰子的點數之的方法和前面講的一樣,即再次把n-1個骰子分成兩堆------第一個和剩下的n-2個。n個骰子,每個骰子6個面,總共有6n個組合。這6n個組合之中肯定有重複的,我們知道其範圍是n~6n,對於每種情況我們可以用緩衝機制記錄下來,每當其發生一次我們令其對應的單元加1。

我們定義一個長度為6n-n+1的數組,和為s的點數出現的次數儲存到數組第s-n個元素裡。為什麼是6n-n+1呢?因為n個骰子的和最少是n,最大是6n,介於這兩者之間的每一個情況都可能會發生,總共6n-n+1種情況。下面是java源碼:

 1     private static final int g_maxValue = 6; 2     //基於遞迴求骰子點數,時間效率不高 3     public static void PrintProbability(int number){ 4         if(number<1) return; 5         int maxSum = number*g_maxValue; 6         int[] pProbabilities = new int[maxSum-number+1]; 7         //初始化,開始統計之前都為0次 8         for(int i=number;i<=maxSum;i++){ 9             pProbabilities[i-number] = 0;10         }11         double total = Math.pow(g_maxValue,number);12         //probability(number,pProbabilities);這個Function Computen~6n每種情況出現的次數13         probability(number,pProbabilities);14         for(int i=number;i<=maxSum;i++){15             double ratio = pProbabilities[i-number]/total;16             System.out.println("i: "+i+" ratio: "+ratio);17         }18     }19     public static void probability(int number,int[] pProbabilities){20         for(int i=1;i<=g_maxValue;i++){//從第一個骰子開始21             probability(number,number,i,pProbabilities);22         }23     }24     //總共original個骰子,當前第 current個骰子,當前的和,貫穿始終的數組25     public static void probability(int original,int current,int sum,int[] pProbabilities){26         if(current==1){27             pProbabilities[sum-original]++;28         }else{29             for(int i=1;i<=g_maxValue;i++){30                 probability(original,current-1,sum+i,pProbabilities);31             }32         }33     }

這種方法思路非常簡潔,但是遞迴實現會存在子問題重複求解的情況發生,所以當number很大的時候,其效能會慢的讓人不能接受。

解法二:基於迴圈,時間效能好

遞迴一般是自頂向下的分析求解,而基於迴圈的方法則是自底向上。基於迴圈的一般需要更少的空間和更少的時間,效能較好,但是一般代碼比較難懂。

書上的講解比較簡單,代碼沒有注釋,這裡本人用java實現了書本上的方法,注釋比較詳細。

 1  //基於迴圈求骰子點數 2     public static void PrintProbability_1(int number){ 3         if(number<1){ 4             return; 5         } 6         int[][] pProbabilities = new int[2][g_maxValue*number +1]; 7         for(int i=0;i<g_maxValue;i++){//初始化數組 8              pProbabilities[0][i] = 0; 9              pProbabilities[1][i] = 0;10         }11         int flag = 0;12         for(int i=1;i<=g_maxValue;i++){//當第一次拋擲骰子時,有6種可能,每種可能出現一次13             pProbabilities[flag][i] = 1;14         }15         //從第二次開始擲骰子,假設第一個數組中的第n個數字表示骰子和為n出現的次數,16         //在下一迴圈中,我們加上一個新骰子,此時和為n的骰子出現次數應該等於上一次迴圈中骰子點數和為n-1,n-2,n-3,n-4,n-5,17         //n-6的次數總和,所以我們把另一個數組的第n個數字設為前一個數組對應的n-1,n-2,n-3,n-4,n-5,n-6之和18         for(int k =2;k<=number;k++){19             for(int i=0;i<k;i++){//第k次擲骰子,和最小為k,小於k的情況是不可能發生的!所以另不可能發生的次數設定為0!20                 pProbabilities[1-flag][i] = 0;21             }22             for(int i=k;i<=g_maxValue*k;i++){//第k次擲骰子,和最小為k,最大為g_maxValue*k23                 pProbabilities[1-flag][i] = 0;//初始化,因為這個數組要重複使用,上一次的值要清024                 for(int j=1;j<=i&&j<=g_maxValue;j++){25                     pProbabilities[1-flag][i] += pProbabilities[flag][i-j];26                 }27             }28             flag = 1-flag;29         }30         double total = Math.pow(g_maxValue, number);31         for(int i=number;i<=g_maxValue*number;i++){32             double ratio = pProbabilities[flag][i]/total;33             System.out.println("sum: "+i+" ratio: "+ratio);34         }35     }

運行結果:

sum: 6 ratio: 2.143347050754458E-5
sum: 7 ratio: 1.286008230452675E-4
sum: 8 ratio: 4.501028806584362E-4
sum: 9 ratio: 0.0012002743484224967
sum: 10 ratio: 0.002700617283950617
sum: 11 ratio: 0.005401234567901234
sum: 12 ratio: 0.00977366255144033
sum: 13 ratio: 0.016203703703703703
sum: 14 ratio: 0.02488425925925926
sum: 15 ratio: 0.03570816186556927
sum: 16 ratio: 0.048161008230452676
sum: 17 ratio: 0.061213991769547324
sum: 18 ratio: 0.07353823731138547
sum: 19 ratio: 0.08371913580246913
sum: 20 ratio: 0.09047067901234568
sum: 21 ratio: 0.09284979423868313
sum: 22 ratio: 0.09047067901234568
sum: 23 ratio: 0.08371913580246913
sum: 24 ratio: 0.07353823731138547
sum: 25 ratio: 0.061213991769547324
sum: 26 ratio: 0.048161008230452676
sum: 27 ratio: 0.03570816186556927
sum: 28 ratio: 0.02488425925925926
sum: 29 ratio: 0.016203703703703703
sum: 30 ratio: 0.00977366255144033
sum: 31 ratio: 0.005401234567901234
sum: 32 ratio: 0.002700617283950617
sum: 33 ratio: 0.0012002743484224967
sum: 34 ratio: 4.501028806584362E-4
sum: 35 ratio: 1.286008230452675E-4
sum: 36 ratio: 2.143347050754458E-5

 

《劍指offer》 面試題43 n個骰子的點數 (java)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.