参考博客:https://blog.csdn.net/liu_12345_liu/article/details/103218096
import org.junit.Test;
/**
* 面试题60:n个骰子的点数
* 题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为 s,输n,打印出 s 的所有可能的值出现的概率。
*
* @author
* @create 2021-04-19 21:53
*/
public class Solution60 {
public static void main(String[] args) {
PrintProbability(5);
}
/**
* 方法一:基于递归实现
* 剑指Offer
* @param diceNumber
*/
private static final int DiceMaxValue = 6;
public static void PrintProbability(int diceNumber) {
if (diceNumber < 1){
return;
}
int maxValue = DiceMaxValue * diceNumber;
int[] problities = new int[maxValue - diceNumber + 1];//统计每个点数出现的次数
// probability(diceNumber,problities);
probabilityOne(diceNumber,diceNumber,0,problities);
double total = Math.pow(DiceMaxValue,diceNumber);
for (int i = 0; i < problities.length; i++) {
double ratio = problities[i] / total;
System.out.println(ratio);
}
}
public static void probability(int diceNumber, int[] probabilities){
for (int surfaceSum = 1; surfaceSum <= DiceMaxValue; surfaceSum++) {
//第一个筛子的点数有 1~DiceMaxValue种可能值。
probability(diceNumber,diceNumber,surfaceSum,probabilities);
}
}
public static void probability(int diceNumber, int curDiceIndex, int sum, int[] probabilities){
if (curDiceIndex == 1){
// 这里为什么是 1 呢,因为最开始的时候是从diceNumber开始的,而不是从diceNumber-1开始的。
probabilities[sum - diceNumber]++;//统计次数
}else {
//其他筛子的点数
for (int i = 1; i <= DiceMaxValue; i++) {
probability(diceNumber,curDiceIndex-1,sum+i,probabilities);
}
}
}
/**
* 将上面两个方法整合为一个方法
* @param diceNumber
* @param curDiceIndex
* @param sum
* @param probability
*/
public static void probabilityOne(int diceNumber, int curDiceIndex, int sum, int[] probability){
if (curDiceIndex == 0){
probability[sum - diceNumber]++;//统计每个和出现的次数
}else {
for (int i = 1; i <= DiceMaxValue; i++) {
//这个思路跟求排列差不多
probabilityOne(diceNumber,curDiceIndex-1,sum+i,probability);
}
}
}
@Test
public void test(){
PrintProbabilityFor(5);
}
/**
* 方法二:循环实现
* 考虑用一个二维数组来存储骰子点数的每个总数出现的次数。
* @param diceNumber
*/
public static void PrintProbabilityFor(int diceNumber){
if (diceNumber < 1){
return;
}
int maxValue = diceNumber * DiceMaxValue;
int[][] probabilities = new int[2][maxValue + 1];
int flag = 0;
// 只有一个骰子的时候我们将各个和出现的次数都初始化为1
for (int i = 1; i <= DiceMaxValue; i++) {
probabilities[flag][i] = 1;
}
for (int k = 2; k <= diceNumber; k++) {
// 1-flag表示当前我们需要计算的k个骰子的点数和
for (int i = 0; i < k; i++) {
probabilities[1-flag][i] = 0;
}
for (int i = k; i <= DiceMaxValue*k ; i++) {
probabilities[1-flag][i] = 0;
for (int j = 1; j < i && j <= DiceMaxValue; j++) {
probabilities[1-flag][i] += probabilities[flag][i-j];
}
}
flag = 1 - flag;
}
double total = Math.pow(DiceMaxValue,diceNumber);
for (int i = diceNumber; i <= DiceMaxValue*diceNumber; i++) {
double ratio = probabilities[flag][i] / total;
System.out.println(ratio);
}
}
}