问题

n个骰子朝上的数之和为s,求s的所有可能以及概率

分析问题

如果是用笨方法,一般人最开始都会想到笨方法,那就是枚举法

举个例子,比如两个骰子,第一个骰子的结果为1,2,3,4,5,6,两个骰子的结果是2,3,4,5,6,7;3,4,5,6,7,8;4,5,6,7,8,9;……7,8,9,10,11,12,共三十六种,用n平方size的数组记录这36个结果

仔细分析可以发现其实这其中有很多是重复的,所以去除重复,考虑最小的应该是2,也就是n,最大的应该是12,也就是6n

所以所有的结果应该只有6n-n+1=5n+1种,如果我们开辟一个最大index=6n的数组也就是size为6n+1的数组就可以放下这所有的结果,但是其中index为0-(n-1)的位置上没有数放,这里我们有两种解决方案,一种是就让它空着,这样的好处是,结果为s的就可以直接放在index为s的位上,不过如果我们想节省这部分的空间,可以将所有数据往前移一下,也就是把和为s的放在s-n上即可,这样我们就只需要size为5n+1的数组

所以我们再声明一个结果数组,5n+1大小,通过遍历前面的n平方大小的数组,出现和为s就在5n+1大小的s-n位上加1即可

这样的方式,时间复杂度为n平方,可见并不理想,我们可以降低时间复杂度

首先想到是否能退化问题,比如n个骰子与n-1个骰子之间的关系,比如n个骰子的结果是n-1个骰子的结果分别加上1-6而得,于是n-1个骰子的结果又是n-2个骰子的结果分别再加上1-6所得

但递归的方法并不是很好,很多重复计算,重复计算的问题可以考虑斐波拉契计算过程,我们最后提出一种以空间换时间的方法,也是传统的记录中间结果的方法,根斐波拉契的优化很像,将某些中间结果存起来以减少递归过程的重复计算问题

解决问题

主体在如何计算次数,将次数存到数组中,由于要用到递归,我们最好单独写一个base函数,这是我的经验,base函数中的参数要包括递归的时候要用到的那些变量,比如总的n,现在的n,以及现在的sum,以及贯穿始终的次数数组

static void baseProbabilities(int numTotal,int numCur,int sum,int[] probabilities){

if (numCur==1) {

probabilities[sum-numTotal]++;

}else {

for (int i = 1; i <=g_maxValue ; i++) {

baseProbabilities(numTotal, numCur-1, sum+i, probabilities);

}

}

}

而计算次数的时候就是去调用这个base的函数

for (int i = 1; i <=g_maxValue; i++) {

baseProbabilities(number, number, i, probabilities);

}

考虑n=2时的递归过程,首先nT=2,nC=2,sum=1,表明第一个骰子甩出一个1,由于nC=2表明现在有两个骰子,所以进入else部分,i又从1到6循环,表明这是进入到第二个骰子在甩了,首先i为1,表明又甩出一个1,这时候nC=1,就将2-n的位置上加1,表明结果为2的次数加1,然后退到上一层,i++,此时还是第二个骰子在甩,甩出一个2,此时sum=3,nC=1,所以在和为3的位置上加1,一直这样,到了和为7的位置上加1的时候,会退到在上一次循环,这时候表明第一个骰子甩出了一个2,此时进入第二个骰子,依次会出现和为3,4,5,6,7,8的结果,然后再在相应位置上加1即可

优化方法

我们需要将中间值存起来以减少递归过程中的重复计算问题,可以考虑我们用两个数组AB,A在B之上得到,B又在A之上再次得到,这样AB互相作为对方的中间值,其实这个思想跟斐波拉契迭代算法中用中间变量保存n-1,n-2的值有异曲同工之妙

我们用一个flag来实现数组AB的轮换,由于要轮转,我们最好声明一个二维数组,这样的话,如果flag=0时,1-flag用的就是数组1,如果flag=1时,1-flag用的就是数组0,

int[][] probabilities=new int[2][];

probabilities[0]=new int[g_maxValue*number+1];

probabilities[1]=new int[g_maxValue*number+1];

我们以probabilities[0]作为初始的数组,那么我们对这个数组进行初始化是要将1-6都赋值为1,说明第一个骰子投完的结果存到了probabilities[0]

然后就是第二个骰子,第二个骰子的结果存到probabilities[1],是以probabilities[0]为基础的,此时和为s的次数就是把probabilities[0]中和为s-1,s-2,s-3,s-4,s-5,s-6的次数加起来即可

int temp=0;

for(int j=1;j<=i && j<=g_maxValue;++j)

temp+=probabilities[flag][i-j];

probabilities[1-flag][i]=temp;

而第k次用k个骰子那么要更新的结果范围就是k到maxValue*k

所以连起来就是

for(int i=k;i<=g_maxValue*k;++i)

{

int temp=0;

for(int j=1;j<=i && j<=g_maxValue;++j)

temp+=probabilities[flag][i-j];

probabilities[1-flag][i]=temp;

}

然后就需要把probabilities[1]作为中间值数组,这里我们把flag赋值为1-flag即可,是不是很神奇!

flag=1-flag;

java计算筛子概率_剑指Offer解题报告(Java版)——n个骰子的点数 43相关推荐

  1. java 数组中某个数出现的概率_剑指Offer解题报告(Java版)——排序数组中某个数的个数 38...

    分析问题 问题只需要找到排序数组中某个数K的个数,由于已经是排序了,K一定是在一堆的,所以我们只需要找到第一个K的index1,然后找到最后一个K的index2就可以了 而寻找K的过程我们一般通过二分 ...

  2. java翻转单词顺序split_剑指offer解题报告(Java版)——翻转单词顺序 左旋字符串 42...

    引言 这种翻转的问题会遇到很多,其实就是一个倒序的问题,对于第一个题只是想翻转单词的顺序,而并不想把整个字符串翻转了,如果完全翻转的话,比如I am a student.中所有字符翻转得到.tnedu ...

  3. 剑指offer有python版吗_剑指Offer算法类题目[Python版]

    标签:重复   作用   coding   面试   medium   mba   none   fas   utf-8 面试题012 数值的整数次方 解题思路1 考虑所有情况,循环连乘 代码: de ...

  4. java 最大子数组_[剑指offer题解][Java]连续子数组的最大和

    前言 众所周知,<剑指offer>是一本"好书". 如果你是个算法菜鸡(和我一样),那么最推荐的是先把剑指offer的题目搞明白. 对于剑指offer题解这个系列,我的 ...

  5. java计算筛子概率_使用excel计算骰子输赢概率

    如何得到使用3个骰子掷赢4个骰子的概率(每个骰子的点数为1-6,点数一样算输) 分为3步解决: 第一步.计算n个骰子得到m点数的分布 1个骰子能得到1.2.3.4.5.6点数,每个点数出现的方式只有1 ...

  6. java单个数组求积_[剑指offer][Java]构建乘积数组

    题目 给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]A[1]...A[i-1]A[i+1]...A[n-1].不能使用除法. 程 ...

  7. java listnode 合并链表_剑指offer:合并两个排序的链表(Java)

    1.问题描述 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. 2.思路 方法1:非递归方法 根据题目这个很类似排序中的外排过程,两个数组分别排好序,然后再 ...

  8. 剑指 Offer(专项突击版)Java 持续更新....

    剑指 Offer(专项突击版) 刷题链接: https://leetcode-cn.com/problem-list/e8X3pBZi/?page=1 No.001 题目: 整数除法 1. 刷题链接: ...

  9. 字符串全排列算法_C#版_剑指OFFER

    字符串全排列算法_C#版_剑指OFFER 题目描述 ​题目描述 输入一个长度为 n 字符串,打印出该字符串中字符的所有排列,你可以以任意顺序返回这个字符串数组. 例如输入字符串ABC,则输出由字符A, ...

最新文章

  1. java 泛型 .net_Java基础11:Java泛型详解
  2. 如何做一场高质量的分享?
  3. 机器学习(machine learning)之AdaBoost算法
  4. 超出了GC开销限制– Java堆分析
  5. pat 乙级 1020 月饼(C++实现)
  6. python代码-让你的Python代码实现类型提示功能
  7. python图层_Python叠加矩形框图层2种方法及效果
  8. 基于OleDb的Excel数据访问
  9. Win XP局域网设置及其无法访问解决方案
  10. [21] Mesh法线的生成算法
  11. Linux基础知识以及常见面试问题
  12. 网页端启动服务器控制台程序,在ASP.Net(C#)中调用服务器端的控制台应用程序
  13. 苹果x与苹果xs的区别_x和XS的区别到底在哪里,我来告诉你
  14. java cap是什么_分布式CAP是什么?它的原理是什么?
  15. ncre计算机职业英语,NCRE计算机职业英语一级考试样卷
  16. json文件的读与写
  17. java aspose.words 生成word目录和更新目录
  18. 中国菜刀使用教程--ctf 文件上传
  19. 连接池中的最大连接数和最小连接数
  20. 第十九节:依次逐个点亮LED之后,再依次逐个熄灭LED的跑马灯程序。

热门文章

  1. hadoop配置安装
  2. Solr搜索引擎 — 通过mysql配置数据源
  3. webpack 开发模式管理 Development
  4. BZOJ - 3963: [WF2011]MachineWorks
  5. python 统计单词个数---不去重
  6. 安卓中事件绑定的写法
  7. vs2013编译 protoBuffer编译出现的问题
  8. 微信基础服务肯定不收费
  9. FreeBSD学习笔记25-安装DHCP服务
  10. 平板python_Wacom平板电脑的Python示例