题目描述
// 60. n个骰子的点数
// 力扣
// 把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,
// 打印出s的所有可能的值出现的概率。
// 你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 n
// 个骰子所能掷出的点数集合中第 i 小的那个的概率。
// 这题其实可理解为求所有掷出点数的概率
题解
// 力扣
// 如果n=1个骰子,可能出现的值的和为[1-6]一共6种,每个值概率相同,
// 如果n=2个骰子,可能出现的值的和为[2-12]共11种,
// 和为s=2的概率为1/6 * 1/6,
// 和为s=3的概率为1/6 * 1/6 (1和2) + 1/6 * 1/6 (2和1)。
// 如果n=3个骰子,可能出现的值的和为[3-18]共16种,
// 和为s=3的概率为1/6 * 1/6 * 1/6,
// 和为s=4的概率为1/6 * 1/6 * 1/6 (1 1 2) + 1/6 * 1/6 * 1/6 (2 1 1)
// + 1/6 * 1/6 * 1/6 (1 2 1)
//
// 可以看出,n个骰子的点数可以分解为n-1个骰子的点数遇到1个骰子的点数,
// 如此循环,其实是一个动态规划问题。
// 我们用数组下标作为骰子点数来理解,1个骰子的每一个点数出现的概率是1/6,
// 由于骰子从1开始,一路动态规划到n个骰子,所以我们将初始化n-1个骰子
// 概率为double[] pre = {1/6d, 1/6d, 1/6d, 1/6d, 1/6d, 1/6d}。
// 我们称pre为点数-概率计数数组,索引就是点数,元素就是点数(和)对应的概率
//
// for循环从2到n遍历会递增的骰子数量,记为i,假设n=2,则此时i=n=2,
// 根据骰子数n构建目标概率数组temp,n=2可以分解为"n-1个"和"1个骰子",
// 第二层for循环遍历"n-1骰子"的概率pre[j],再第三层for循环遍历"1个骰子",
// 的概率(就是1/6,所以实际就是for循环遍历6次,每次乘1/6),
// 下标就是骰子点数,所以temp[j + t] += pre[j] * 1/6。
// 那么此时"n-1(n-1=1)个骰子"的第一个点数(j=0),遇到"1个骰子"的第一个
// 点数(t=0)(点数就是下标,两边都是第一个点数,所以点数之和是0+0
// 所以点数之和的概率是temp[0 + 0](j=t=0))
// 的概率是temp[0 + 0] = pre[j]*1/6 = 1/6*1/6。以此类推,
// 第三层for循环第一次完成之后,"n-1个骰子"的第一个点数,
// 遇到"1个骰子"的6个点数之和的概率都会被算出来,存入相应temp中,
// temp的索引就是相应的点数之和,temp的元素就是点数之和对应的概率。
//
// "n-1个骰子"的所有点数概率(pre同样也是,索引记录点数,元素记录概率)
// 之后都会和"1个骰子"的6个点数计算相遇概率,并将计算好的概率存入temp中
// 最后第二层循环完成,temp赋给pre,第一层for循环开始下一个骰子的计算。
//
// 所有循环完成,返回点数-概率计数数组pre。
// 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
// 内存消耗:38.6 MB, 在所有 Java 提交中击败了74.58%的用户
class Solution {
public double[] dicesProbability(int n) {
double[] pre = {1/6d, 1/6d, 1/6d, 1/6d, 1/6d, 1/6d};
for (int i = 2; i <= n; i++) {
double temp[] = new double[i*6 - i + 1];
for (int j = 0; j < pre.length; j++) {
for (int t = 0; t < 6; t++)
temp[j + t] += pre[j] * 1/6;
}
pre = temp;
}
return pre;
}
}
// 可以试着将过程打印出来
class Solution {
public double[] dicesProbability(int n) {
double[] pre = {1/6d, 1/6d, 1/6d, 1/6d, 1/6d, 1/6d};
for (int i = 2; i <= n; i++) {
double temp[] = new double[i*6 - i + 1];
for (int j = 0; j < pre.length; j++) {
arrPrint(temp);
for (int t = 0; t < 6; t++)
temp[j + t] += pre[j] * 1/6;
}
pre = temp;
}
return pre;
}
// 辅助函数:将int[] 打印出来
private static void arrPrint(double[] arr) {
StringBuilder str = new StringBuilder();
str.append("[");
for (double v : arr) {
str.append(v + ", ");
}
str.delete(str.length() - 2, str.length());
str.append("]");
System.out.println(str.toString());
}
}