劍指 Offer 60. n個骰子的點數

題目:

劍指 Offer 60. n個骰子的點數
在這裏插入圖片描述

題解:

點數之和:
在這裏插入圖片描述
概率:
在這裏插入圖片描述

1. 解釋一:

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

2. 解釋二:

在這裏插入圖片描述
在這裏插入圖片描述

3. 疑難點:

在這裏插入圖片描述
在這裏插入圖片描述

代碼:

注意:
時間複雜度:O(n * 5n * 6) == O(30 * n²), 又因爲1 <= n <= 11,因此,即便是三層for循環,但最大時間複雜度也就是O(3630),也就是一共才循環3000多次,這種效率近似於線性遍歷O(N),因此代碼執行速度還是很快的。

public class 面試題60 {

    public static double[] twoSum(int n) {
        // 狀態定義,dp[i][j]表示骰子個數爲i時點數j可能出現的次數,dp[i][s]表示i個骰子擲出s點的次數
        int dp[][] = new int[n + 1][6 * n + 1];
        // 初始狀態
        for(int i = 1; i <= 6; i++)
        {
            dp[1][i] = 1; // 表示一個骰子擲出i點的次數爲1
        }
        for(int i = 2; i <= n; i++) // 表示骰子的個數
        {
            for(int s = i; s <= 6 * i; s++) // 表示可能會出現的點數之和
            {
                for(int j = 1; j <= 6; j++) // 表示當前這個骰子可能擲出的點數
                {
                    if(s - j < i - 1) // (總點數 s) - (當前的點數 j) >= (前i-1個骰子的最小點數之和i-1)
                    {
                        break;  // 如果不滿足上述條件,則不存在這種情況,直接跳出循環即可
                    }
                    dp[i][s] += dp[i - 1][s - j]; // 當前 n 個骰子出現的點數之和等於前一次出現的點數之和加上這一次出現的點數
                }
            }
        }
        double total = Math.pow(6, n); // 擲出 n 次點數出現的所有情況
        double ans[] = new double[5 * n + 1]; // 因爲最大就只會出現 5*n+1 種點數
        for(int i = n; i <= 6 * n; i++)
        {
            ans[i - n] = dp[n][i] / total; // 第i小的點數出現的概率
        }
        return ans;
    }

    public static void main(String[] args) {
        int n = 2;
        double res[] = twoSum(n);
        for(int i = 0; i < res.length; i++)
        {
            System.out.printf("%.5f  ", res[i]);
        }
        System.out.println();
    }
}

參考:

  1. 【n個骰子的點數】:詳解動態規劃及其優化方式
  2. 動態規劃(註釋清晰)
  3. 動態規劃(掃了一圈,俺是最短的)
  4. C++ 動態規劃解法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章