Loading

剑指 Offer 60. n个骰子的点数

 

思路

方法:动态规划

用dp[i][j]表示掷完 i 个骰子之后其点数之和为 j 的总次数,这可以由

投掷完 n-1 枚骰子后,对应点数 j-1, j-2, j-3, ... , j-6 出现的次数之和转化过来。

 

即:

 

 1 class Solution {
 2 public:
 3     vector<double> dicesProbability(int n) {
 4         vector<vector<int>> dp(n+1, vector<int>(6*n+1, 0));
 5         
 6         for(int i = 1; i <= 6; ++i) {
 7             dp[1][i] = 1;
 8         }
 9 
10         for(int i = 2; i <= n; ++i) {
11             //i个骰子能抛出的点数之和最小为i,最大为6*i
12             for(int j = i; j <= 6*i; ++j) {
13                 for(int k = 1; k <= 6; ++k) {
14                     if(j - k <= 0) break;
15                     dp[i][j] += dp[i-1][j-k];
16                 }
17             }
18         }
19 
20         int total = pow(6, n);
21         vector<double> res;
22         for(int i = n; i <= 6*n; ++i) {
23             res.push_back(dp[n][i] * 1.0 / total);
24         }
25 
26         return res;
27     }
28 };

复杂度分析

时间复杂度:O(n2)

空间复杂度:O(n*6*n)

 

空间优化:

 1 class Solution {
 2 public:
 3     vector<double> dicesProbability(int n) {
 4         vector<int> dp(6*n+1, 0);
 5 
 6         for(int i = 1; i <= 6; ++i) {
 7             dp[i] = 1;
 8         }
 9 
10         for(int i = 2; i <= n; ++i) {
11             for(int j = 6*i; j >= i; --j) {
12                 dp[j] = 0;  //dp[j]表示前i个骰子点数之和为j的次数
13                 for(int k = 1; k <= 6; ++k) {
14                     if(j-k < i-1) break;    //前i-1个骰子点数之和最小为i-1
15                     dp[j] += dp[j-k];       //所以这里只需要加到前一轮的最小和
16                 }
17             }
18         }
19 
20         int total = pow(6, n);
21         vector<double> res;
22         for(int i = n; i <= 6*n; ++i)
23             res.push_back(dp[i] * 1.0 / total);
24         
25         return res;
26     }
27 };

复杂度分析

时间复杂度:O(n2)

空间复杂度:O(6*n)

posted @ 2020-11-15 11:01  拾月凄辰  阅读(139)  评论(0编辑  收藏  举报