classSolution{// 提高程序扩展性publicint maxValue =6;publicdouble[]twoSum(int n){if(n <1)returnnewdouble[]{};// 最大和为6n,最小和为n,可能的和有 6n - n + 1 种int maxSum = n * maxValue;// 定义一个长度为6n - n + 1的数组,每个元素代表每个可能的和s的出现次数int[] probabilities =newint[maxSum - n +1];probability(n, probabilities);double[] ans =newdouble[probabilities.length];// 由排列组合可知n个骰子排列数次数为6^ndouble total = Math.pow(maxValue, n);for(int i = n; i <= maxSum ; i++){
ans[i - n]=(double)probabilities[i - n]/ total;}return ans;}privatevoidprobability(int n,int[] probabilities){// 把n个骰子分成两部分:第一部分一个,有1-6种;第二部分n-1个。// 计算1-6中每个点数与剩下n-1个骰子的点数和for(int i =1; i <= maxValue; i++){probability(n, n, i, probabilities);}}// current 为当前剩余的骰子数; sum为当前的和privatevoidprobability(int n,int current,int sum,int[] probabilities){if(current ==1){
probabilities[sum - n]++;}else{for(int i =1; i <= maxValue; i++){probability(n, current -1, sum + i, probabilities);}}}}
解法二 动态规化
classSolution{// 提高程序扩展性publicint maxValue =6;publicdouble[]twoSum(int n){if(n <1)returnnewdouble[]{};// 最大和为6n,最小和为n,可能的和有 6n - n + 1 种int maxSum = n * maxValue;int[][] probablilities =newint[2][maxSum +1];
Arrays.fill(probablilities[0],0);
Arrays.fill(probablilities[1],0);int flag =0;// 第一轮循环:只有一个骰子时1~6每个数字出现的次数为1for(int i =1; i <= maxValue; i++)
probablilities[flag][i]=1;// 第二轮循环: 每次增加一个骰子,范围为2~nfor(int k =2; k <= n; k++){// 另一个数组和为前k-1为的数字出现次数为0for(int i =0; i < k;++i)
probablilities[1-flag][i]=0;// 计算k~maxValue * k之间每个和出现的次数for(int i = k; i <= maxValue * k; i++){// 先初始化为0
probablilities[1-flag][i]=0;for(int j =1; j <= i && j <= maxValue; j++){
probablilities[1-flag][i]+= probablilities[flag][i-j];}}// 交换数组
flag =1-flag;}double total = Math.pow(maxValue, n);double[] ans =newdouble[maxSum - n +1];for(int i = n; i <= maxSum; i++){
ans[i-n]= probablilities[flag][i]/total;}return ans;}}