原题:把n个骰子扔到地上,所有骰子朝上一面的点数之后为s. 输入n,打印出s所有可能的值出现的概率。(每个骰子6个面,点数从1到6)
解法一:基于递归,时间效率不高
递归的思想一般是分而治之,把n个骰子分为第一个和剩下的n-1个。先计算第一个骰子每个点数出现的次数,再计算剩余n-1个骰子出现的点数之和。求n-1个骰子的点数之的方法和前面讲的一样,即再次把n-1个骰子分成两堆------第一个和剩下的n-2个。n个骰子,每个骰子6个面,总共有6n个组合。这6n个组合之中肯定有重复的,我们知道其范围是n~6n,对于每种情况我们可以用缓存机制记录下来,每当其发生一次我们令其对应的单元加1。
我们定义一个长度为6n-n+1的数组,和为s的点数出现的次数保存到数组第s-n个元素里。为什么是6n-n+1呢?因为n个骰子的和最少是n,最大是6n,介于这两者之间的每一个情况都可能会发生,总共6n-n+1种情况。
这种方法思路非常简洁,但是递归实现会存在子问题重复求解的情况发生,所以当number很大的时候,其性能会慢的让人不能接受。
解法二:基于循环,时间性能好(还是没有完全搞懂,自己写还是不行)
递归一般是自顶向下的分析求解,而基于循环的方法则是自底向上。基于循环的一般需要更少的空间和更少的时间,性能较好,但是一般代码比较难懂。
代码:
public class Offer43 {
private static final int maxValue = 6;
//方法1, 递归,效率低
public static void printProbability(int number){
if(number <1)
return ;
int maxSum = number * maxValue;
int [] probabilities = new int[maxSum - number+1];
for(int i = number;i <= maxSum;i++)
probabilities[i-number] = 0;//初始化,开始统计之前都为0次
double total = Math.pow(maxValue, number);
probability(number, probabilities);
//probability(number,pProbabilities);这个函数计算n~6n每种情况出现的次数
for(int i = number;i<=maxSum;i++){
double ratio = probabilities[i-number]/total;
System.out.println("i: "+ i+" ratio: "+ratio);
}
}
public static void probability(int number, int[] probabilities) {
for(int i = 1;i<= maxValue;i++){
probability(number, number, i, probabilities);
}
}
//总共original个骰子,当前第 current个骰子,当前的和,贯穿始终的数组
public static void probability(int original, int current, int sum,int[] probabilities) {
if(current == 1)
probabilities[sum-original]++;
else
for(int i = 1;i<=maxValue;i++)
probability(original, current-1, sum+i, probabilities);
}
//方法2, 基于循环,性能好
public void printProbability_2(int number){
if(number<1)
return;
int [][] probabilities = new int[2][maxValue* number+1];
for(int i = 0;i<maxValue;i++){//初始化数组
probabilities[0][i] = 0;
probabilities[1][i] = 0;
}
int flag = 0;
for(int i = 1;i<=maxValue;i++){//当第一次抛掷骰子时,有6种可能,每种可能出现一次
probabilities[flag][i] = 1;
}
//从第二次开始掷骰子,假设第一个数组中的第n个数字表示骰子和为n出现的次数,
//在下一循环中,我们加上一个新骰子,此时和为n的骰子出现次数应该等于上一次循环中骰子点数和为n-1,n-2,n-3,n-4,n-5,
//n-6的次数总和,所以我们把另一个数组的第n个数字设为前一个数组对应的n-1,n-2,n-3,n-4,n-5,n-6之和
for(int k = 2;k<= number;k++){
for(int i = 0;i<k;i++)//第k次掷骰子,和最小为k,小于k的情况是不可能发生的!所以另不可能发生的次数设置为0!
probabilities[1-flag][i] = 0;
for(int i =k;i<= maxValue*k;i++){//第k次掷骰子,和最小为k,最大为g_maxValue*k
probabilities[1-flag][i] = 0;//初始化,因为这个数组要重复使用,上一次的值要清0
for(int j = 1;j<=i && j<=maxValue;j++)
probabilities[1-flag][i] += probabilities[flag][i-j];
}
flag = 1-flag;
}
double total = Math.pow(maxValue, number);
for(int i = number;i<=maxValue*number;i++){
double ratio = probabilities[flag][i]/total;
System.out.println("sum: "+i+"ratio: "+ratio);
}
}
public static void main(String[] args) {
Offer43 of43 = new Offer43();
//功能测试,1,1个筛子的各点数的概率
int number1 = 1;
//of43.printProbability(number1);
//of43.printProbability_2(number1);
//功能测试,2,2个筛子的各点数的概率
int number2 = 2;
//of43.printProbability(number2);
//of43.printProbability_2(number2);
//功能测试,3,2个筛子的各点数的概率
int number3 = 3;
//of43.printProbability(number3);
//of43.printProbability_2(number3);
//功能测试,4,2个筛子的各点数的概率
int number4 = 4;
//of43.printProbability(number4);
//of43.printProbability_2(number4);
//特殊输入测试,5,输入0
int number5 = 0;
//of43.printProbability(number5);
//of43.printProbability_2(number5);
//性能测试,6,输入比较大的数字,如11
int number6 = 11;
//of43.printProbability(number6);
of43.printProbability_2(number6);
}
}
运行结果:
i: 1 ratio: 0.16666666666666666
i: 2 ratio: 0.16666666666666666
i: 3 ratio: 0.16666666666666666
i: 4 ratio: 0.16666666666666666
i: 5 ratio: 0.16666666666666666
i: 6 ratio: 0.16666666666666666
i: 2 ratio: 0.027777777777777776
i: 3 ratio: 0.05555555555555555
i: 4 ratio: 0.08333333333333333
i: 5 ratio: 0.1111111111111111
i: 6 ratio: 0.1388888888888889
i: 7 ratio: 0.16666666666666666
i: 8 ratio: 0.1388888888888889
i: 9 ratio: 0.1111111111111111
i: 10 ratio: 0.08333333333333333
i: 11 ratio: 0.05555555555555555
i: 12 ratio: 0.027777777777777776
i: 3 ratio: 0.004629629629629629
i: 4 ratio: 0.013888888888888888
i: 5 ratio: 0.027777777777777776
i: 6 ratio: 0.046296296296296294
i: 7 ratio: 0.06944444444444445
i: 8 ratio: 0.09722222222222222
i: 9 ratio: 0.11574074074074074
i: 10 ratio: 0.125
i: 11 ratio: 0.125
i: 12 ratio: 0.11574074074074074
i: 13 ratio: 0.09722222222222222
i: 14 ratio: 0.06944444444444445
i: 15 ratio: 0.046296296296296294
i: 16 ratio: 0.027777777777777776
i: 17 ratio: 0.013888888888888888
i: 18 ratio: 0.004629629629629629
i: 4 ratio: 7.716049382716049E-4
i: 5 ratio: 0.0030864197530864196
i: 6 ratio: 0.007716049382716049
i: 7 ratio: 0.015432098765432098
i: 8 ratio: 0.02700617283950617
i: 9 ratio: 0.043209876543209874
i: 10 ratio: 0.06172839506172839
i: 11 ratio: 0.08024691358024691
i: 12 ratio: 0.09645061728395062
i: 13 ratio: 0.10802469135802469
i: 14 ratio: 0.11265432098765432
i: 15 ratio: 0.10802469135802469
i: 16 ratio: 0.09645061728395062
i: 17 ratio: 0.08024691358024691
i: 18 ratio: 0.06172839506172839
i: 19 ratio: 0.043209876543209874
i: 20 ratio: 0.02700617283950617
i: 21 ratio: 0.015432098765432098
i: 22 ratio: 0.007716049382716049
i: 23 ratio: 0.0030864197530864196
i: 24 ratio: 7.716049382716049E-4
(输入0,没有输出)
i: 11 ratio: 2.7563619479867003E-9
i: 12 ratio: 3.0319981427853706E-8
i: 13 ratio: 1.8191988856712222E-7
i: 14 ratio: 7.883195171241963E-7
i: 15 ratio: 2.759118309934687E-6
i: 16 ratio: 8.27735492980406E-6
i: 17 ratio: 2.2042626498049643E-5
i: 18 ratio: 5.3272207368738955E-5
i: 19 ratio: 1.1861176734576369E-4
i: 20 ratio: 2.4595568934274924E-4
i: 21 ratio: 4.7890410665294927E-4
i: 22 ratio: 8.811620566182324E-4
i: 23 ratio: 0.0015397396168506947
i: 24 ratio: 0.0025654645885549855
i: 25 ratio: 0.004089195255211773
i: 26 ratio: 0.006252344010200568
i: 27 ratio: 0.009191017250151005
i: 28 ratio: 0.013014366908203356
i: 29 ratio: 0.017779303589497704
i: 30 ratio: 0.02346520970666311
i: 31 ratio: 0.029953382532409523
i: 32 ratio: 0.037016300926102336
i: 33 ratio: 0.044321114887988504
i: 34 ratio: 0.05144967328511067
i: 35 ratio: 0.05793451091290002
i: 36 ratio: 0.06330709034198999
i: 37 ratio: 0.06715181558694898
i: 38 ratio: 0.0691574823584015
i: 39 ratio: 0.0691574823584015
i: 40 ratio: 0.06715181558694898
i: 41 ratio: 0.06330709034198999
i: 42 ratio: 0.05793451091290002
i: 43 ratio: 0.05144967328511067
i: 44 ratio: 0.044321114887988504
i: 45 ratio: 0.037016300926102336
i: 46 ratio: 0.029953382532409523
i: 47 ratio: 0.02346520970666311
i: 48 ratio: 0.017779303589497704
i: 49 ratio: 0.013014366908203356
i: 50 ratio: 0.009191017250151005
i: 51 ratio: 0.006252344010200568
i: 52 ratio: 0.004089195255211773
i: 53 ratio: 0.0025654645885549855
i: 54 ratio: 0.0015397396168506947
i: 55 ratio: 8.811620566182324E-4
i: 56 ratio: 4.7890410665294927E-4
i: 57 ratio: 2.4595568934274924E-4
i: 58 ratio: 1.1861176734576369E-4
i: 59 ratio: 5.3272207368738955E-5
i: 60 ratio: 2.2042626498049643E-5
i: 61 ratio: 8.27735492980406E-6
i: 62 ratio: 2.759118309934687E-6
i: 63 ratio: 7.883195171241963E-7
i: 64 ratio: 1.8191988856712222E-7
i: 65 ratio: 3.0319981427853706E-8
i: 66 ratio: 2.7563619479867003E-9