剑指 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)