一、题目
把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。
你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率。
示例 1:
输入: 1 输出: [0.16667,0.16667,0.16667,0.16667,0.16667,0.16667] 示例 2:
输入: 2 输出:
[0.02778,0.05556,0.08333,0.11111,0.13889,0.16667,0.13889,0.11111,0.08333,0.05556,0.02778]
限制:
1 <= n <= 11
二、思路
(一)递归
每个骰子出现1-6的概率均为1/6,且n个骰子可以出现的数字范围为[n,6n]。可以使用递归的方法来解决,将其分解为一个骰子出现1-6的情况乘以n-1个骰子可能出现的情况之和。
例如:2个骰子出现3的概率f(2,3)=出现1的概率 x f(1,2)+出现2的概率 x f(2,1)
依次递推
class Solution {
public double[] dicesProbability(int n) {
if( n == 1 ){
double[] res = new double[6];
Arrays.fill(res,1/6d);
return res;
}else{
int len = 6*n-n+1;
double[] res = new double[len];
Arrays.fill(res,0);
int num = n;
double total = Math.pow(6d,n);//所有可能的情况数目
for(int i = 0; i < len; i++){
probability(res,num,n,i,total);
num ++;
}
return res;
}
}
//写入概率的数组,需要的和,还有多少骰子,正在写入res[i]
void probability(double[] res, int num, int rear,int i,double total){
if(rear == 1){
if(num <= 6 && num >= 1){
res[i] += 1/total;
}
}else{
for(int j = 1; j <= Math.min(6,num-rear+1); j++){//num-rear+1:num-(rear-1),即剩下至少每个都为1
probability(res,num-j,rear-1,i,total);
}
}
}
}
(二)动态规划
class Solution {
public double[] dicesProbability(int n) {
if( n == 1 ){
double[] res = new double[6];
Arrays.fill(res,1/6d);
return res;
}else{
double[] res = new double[6];//1个骰子,和为0-5
Arrays.fill(res,1/6d);
for(int i = 2; i <= n; i++){//依次遍历不同个骰子,有n+1个
int len = 5*i+1;//和的可能个数,最大为6*i,最小为i
double[] tmp = new double [len];//i个骰子
for(int j = 0; j < len; j++){//和为j+2i
for(int m = 1; m <= 6; m++){//当前骰子取到的值
if(((j-m+1) < 5*(i-1)+1)&& (j-m+1) >=0){
tmp[j] += 1.0/6.0 * res[j-m+1];//res中是i-1
}
}
}
res = tmp;
}
return res;
}
}
}