1. 程式人生 > >劍指offer:n個骰子的點數(java)

劍指offer:n個骰子的點數(java)

題目:把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個骰子來計算點數和。分析到這裡,我們不難發現這是一種遞迴的思路,遞迴結束的條件就是最後只剩下一個骰子。

    我們可以定義一個長度為6n-n+1的陣列儲存n個骰子的點數和,和為sum的點數出現的次數儲存到第sum-n個元素裡。
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);  
        }  
    }