问题:把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。(1 <= n <= 11)
思路1:递归
将n个骰子分为1和n-1两堆,n-1又可以进行递归,递归结束条件最后只剩下1个。
代码:
class Solution {
public:
double total;
void probabilityCore(int original,int current,int sum,vector<double>& p)
{
if(current==0)
{
p[sum-original]+=1.0/total;
}
else
{
for(int i=1;i<=6;++i)
{
probabilityCore(original,current-1,sum+i,p);
}
}
}
vector<double> twoSum(int n) {
vector<double> res(6*n-n+1,0);
total=pow(6.0,n);
probabilityCore(n,n,0,res);
return res;
}
};
时间复杂度为O(6^n),会超时,空间复杂度O(n)。
思路2:循环
两个数组分别存放两轮中骰子点数和的次数,在一轮循环中,骰子点数和为n的次数放在第一个数组的第n个数字中,下一轮循环,骰子点数和为n的次数为前一个数组的第n-1,n-2,n-3,n-4,n-5,n-6个数字之和。
代码:
class Solution {
public:
vector<double> twoSum(int n) {
vector<double> res(6*n-n+1,0);
vector<vector<int >> nums(2,vector<int> (6*n+1, 0));
int flag=0;
for(int i=1;i<=6;++i)
{
nums[flag][i]=1;
}
for(int k=2;k<=n;++k)
{
for(int i=0;i<k;++i)
nums[1-flag][i]=0;
for(int i=k;i<=k*6;++i)
{
nums[1-flag][i]=0;
for(int j=1;j<=i&&j<=6;++j)
{
nums[1-flag][i]+=nums[flag][i-j];
}
}
flag=1-flag;
}
double total=pow(6.0,n);
for(int i=n;i<=6*n;++i)
res[i-n]=nums[flag][i]/total;
return res;
}
};
复杂度分析:时间复杂度为O(n^2),空间复杂度为O(n)。