题目链接: leetcode.
我:这,,不是个数学题嘛 ,脑子不够,回溯来凑
提交:11 / 11 个通过测试用例 超出时间限制
class Solution {
vector<int> tmp;
public:
void dfs(int index, int sum, int n)//该第index个骰子,之前投的和为sum
{
if(index == n)
{
tmp[sum]++;//记录本次投的情况
return;
}
for(int i = 1;i <= 6;++i)
{
dfs(index+1, sum + i, n);
}
}
vector<double> dicesProbability(int n) {
tmp.resize(n * 6 + 1);
dfs(0, 0, n);
vector<double> ans;
double t = pow(6, n);
for(int i = n;i <= 6 * n;++i)
{
ans.emplace_back(tmp[i] / t);
}
return ans;
}
};
好的,不是数学题,是动态规划 ┭┮﹏┭┮
dp[i][j]
表示i
个骰子,投点数之和为j
发生的次数
对于第n个骰子,想要投出和为m,投的时候只能投出1-6,所以dp[n][m] = dp[n-1][m-1]+dp[n-1][m-2]+...+dp[n-1][m-6]
初始条件是dp[1][1]
到dp[1][6]
都为1
/*
执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:6.4 MB, 在所有 C++ 提交中击败了56.95%的用户
*/
class Solution {
public:
vector<double> dicesProbability(int n) {
vector<vector<int>> dp(12, vector<int>(67));
for(int j = 1;j <= 6;++j)
{
dp[1][j] = 1;
}
for(int i = 2;i <= n;++i)
{
for(int j = i;j <= 6 * i;++j)
{
//x表示第i个能投出的点数
for(int x = 1;j - x > 0 && x < 7;++x)
dp[i][j] += dp[i-1][j-x];
}
}
double sum = pow(6, n);
vector<double> ans;
for(int i = n;i <= 6 * n;++i)
{
ans.emplace_back(dp[n][i] / sum);
}
return ans;
}
};
将空间复杂度从(n^2)优化到O(n)
/*
执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:6.3 MB, 在所有 C++ 提交中击败了65.22%的用户
*/
class Solution {
public:
vector<double> dicesProbability(int n) {
vector<int> dp(67, 0);
for(int j = 1;j <= 6;++j)
{
dp[j] = 1;
}
for(int i = 2;i <= n;++i)
{
for(int j = 6 * i;j >= i ;--j)//从后往前
{
dp[j] = 0;//否则要加上dp[i-2][j-x]啦
//x表示第i个能投出的点数
for(int x = 1;j - x >= i - 1 && x < 7;++x)//边界条件要改变
{
dp[j] += dp[j-x];
}
}
}
double sum = pow(6, n);
vector<double> ans;
for(int i = n;i <= 6 * n;++i)
{
ans.emplace_back(dp[i] / sum);
}
return ans;
}
};
优化的时候最好还是画个图吧,首先从后往前遍历是个技巧,其次遍历的边界条件要考虑好