题目描述
你选择掷出 num 个色子,请返回所有点数总和的概率。
你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 num 个骰子所能掷出的点数集合中第 i 小的那个的概率。
解题思路
参考K神的解题思路:leetcode.cn/problems/ng…
动态规划DP,建立dp数组,dp[i][j] 表示前i个筛子,点数和为 j 的概率。
如何求dp[i][j]?
dp[i][j]的计算建立在dp[i-1][x] 的基础上,举个例子,现在知道第一个筛子,点数和为1,2,3,4,5,6的概率分别为 1/6,1/6,1/6,1/6,1/6,1/6
如何求dp[2][5], 求前两个筛子点数和为5的概率。
dp[2][5] = dp[1][5-1]*1/6 + dp[1][5-2]*1/6 + dp[1][5-3]*1/6 + dp[1][5-4]*1/6 的概率和
也就是(第一个点数为4,第二个点数为1)(第一个点数为3,第二个点数为2)(第一个点数为2,第二个点数为3)(第一个点数为1,第二个点数为4)这些情况的概率和
所以动态转移方程为:
dp[i][j] = dp[i-1][j-1]*1/6 + dp[i-1][j-2]*1/6 + dp[i-1][j-3]*1/6 + dp[i-1][j-4]*1/6 + dp[i-1][j-5]*1/6 + dp[i-1][j-6]*1/6
前提是j要大于等于骰子的点数
代码
可以自己在纸上画一个二维DP数组图看一看,就很清晰了
public class solution {
//https://leetcode.cn/problems/nge-tou-zi-de-dian-shu-lcof/solutions/637778/jian-zhi-offer-60-n-ge-tou-zi-de-dian-sh-z36d/
// dp
// dp[i][j] 表示前i个筛子,点数和为j,的概率,类似于背包问题
// dp[i][j] = dp[i-1][j-1]*1/6 + dp[i-1][j-2]*1/6 + dp[i-1][j-3]*1/6 + dp[i-1][j-4]*1/6 + dp[i-1][j-5]*1/6 + dp[i-1][j-6]*1/6
// TODO 自己在纸上画一个dp数组就行了
public double[] statisticsProbability(int num) {
int height = num+1;
int wid = num*6+1;
double[][] dp = new double[height][wid];
// 初始化第1行
for (int i = 1; i <= 6; i++) {
dp[1][i] = 1.0/6.0d;
}
for (int i = 2; i <= num; i++){
for(int j = i; j <= i*6; j++){
dp[i][j] = 0;
// 置筛子的点数
for(int x =1; x <= 6; x++){
if (x <= j){
dp[i][j] += dp[i-1][j-x]*1.0/6.0d;
}
}
}
}
int begin = num;
int end = num*6;
int index = 0;
double[] res = new double[end - begin + 1];
for(int i = begin; i <= end; i++){
res[index++] = dp[num][i];
}
return res;
}
}