1. 程式人生 > 實用技巧 >leetcode 劍指 Offer 60. n個骰子的點數

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

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

把n個骰子扔在地上,所有骰子朝上一面的點數之和為s。輸入n,打印出s的所有可能的值出現的概率。

你需要用一個浮點數陣列返回答案,其中第 i 個元素代表這 n 個骰子所能擲出的點數集合中第 i 小的那個的概率。

示例 1:

輸入: 1
輸出: [0.16667,0.16667,0.16667,0.16667,0.16667,0.16667]

示例2:

輸入: 2
輸出: [0.02778,0.05556,0.08333,0.11111,0.13889,0.16667,0.13889,0.11111,0.08333,0.05556,0.02778]

限制:

1 <= n <= 11

思路一:動態規劃

動態規劃,如果已知n-1個骰子的每個點數對應的概率,那再求n個骰子的點數對應的概率,就是在n-1個骰子的每個點數上面增加1-6點,這樣就可以組成n個骰子的所有點數,而在原來的點數上增加一個點數概率其實就是多乘了一個1/6, 因為n-1的點數加上1-6點可能會有重疊,因為同一個數字可能有多種組合方式,這些不同的組合的概率應該加起來才是構成這個點數真正的概率。

具體分析可以參考:https://leetcode-cn.com/problems/nge-tou-zi-de-dian-shu-lcof/solution/java-dong-tai-gui-hua-by-zhi-xiong/

 1
class Solution { 2 public double[] twoSum(int n) { 3 double[] pre = {1/6d, 1/6d, 1/6d, 1/6d, 1/6d, 1/6d}; 4 5 // 每次增加一個骰子 6 for(int i = 2; i <= n; i++){ 7 double[] tmp = new double[5 * i + 1]; 8 // 對每個骰子執行:1. 在上一個骰子個數下加上一個骰子,把每個點數都加上0-5, 9
for(int j = 0; j < pre.length; j++){ 10 for(int k = 0; k < 6; k++){ 11 // 因為同一個數字可能有多種組合方式,這些不同的組合的概率應該加起來才是構成這個點數真正的概率 12 tmp[j+k] += pre[j] / 6d; 13 } 14 } 15 pre = tmp; 16 } 17 18 return pre; 19 } 20 }
leetcode 執行用時:0 ms > 100.00%, 記憶體消耗:39.3 MB > 5.04%

複雜度分析:

時間複雜度:6*(n-1)*(5*1+1 + .. + 5*i+1 + ... + 5*(n-1)+1) = 3(n-1)2(5n+2) = 15n3-24n2+3n+6, 根據公式可以看出來,演算法時間複雜度是O(n3)

空間複雜度:需要不斷地建立空間,然後又釋放掉,同時刻存在的兩個最大的記憶體陣列大小分別為(5(n-1)+1)和5n+1, 所以假設每次沒有引用指向陣列後,陣列記憶體會被自動回收的話,那空間複雜度就是O(n)