剑指Offer:n个骰子的点数

把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。

      每个骰子的点数为1~6,n个骰子的点数和最小值为n,最大值为6n,所以n个骰子的点数和s有6n-n+1种情况(例如2个骰子的点数和有:2、3、4、5、6、7、8、9、10、11、12。共6*2-2+1=11种)。另外根据排列组合n个骰子的所有点数的排列数为6n(例如2个骰子的所有点数和共有36种)。我们要求出每种点数和出现的次数,再除以总次数就可以获得每种点数出现的概率了。

解法一:基于递归求骰子点数,时间效率不够高。
      我们将n个骰子分成两堆,一堆为1个骰子,另一堆为n-1个骰子,单独的那一个出现的点数为1~6。我们需要计算n-1个骰子来计算点数和,我们对n-1个骰子再次进行同样的划分。我们用f(n)表示n个骰子出现的点数,f(n)=f(n-1)+f(n-2)+f(n-3)+f(n-4)+f(n-5)+f(n-6)。很显然我们可以用递归实现。

实现代码:

private static void PrintProbaility(int n){
	if(n<=0){
		return;
	}
	int[] pros = new int[6*n-n+1];//因为共有6n-n+1种的s,所有创建一个这样大小的数组来存放每种的次数
	Probaility(pros,n);
	int total = (int) Math.pow(6, n);
	for(int i=n;i<=6*n;i++){
		System.out.println(i+":"+pros[i-n]+"/"+total);
	}
}

private static void Probaility(int[] pros,int n){
	for(int i=1;i<=6;i++){
		Probaility(n,n,i,pros);
	}
}
private static void Probaility(int original,int current,int sum,int[] pros){
	if(current==1){
		pros[sum-original]++;
	}else{
		for(int i=1;i<=6;i++){
			Probaility(original,current-1,i+sum,pros);
		}
	}
}
解法二:基于循环求骰子点数,时间性能好。
      我们可以考虑用两个数组来存储骰子点数的每一个总数出现的次数。在一次循环中,第一个数组中的第 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 之和。 基于这个思路,我们可以写出如下代码:
private static void PrintProbaility(int n) {
	if(n<=0){
		return;
	}
	int[][] pros=new int[2][6*n+1];
	int flag=0;
	for(int i=1;i<=6;i++){ 
		pros[flag][i]=1;
	}
	
	for(int k=2;k<=n;k++){//每次循环表明加上一个新骰子
		for(int i=k;i<=6*k;i++){//n个骰子的s的范围为n~6n
			//核心代码:将n-1~n-6的和加起来
			for(int j=1;j<=i&&j<=6;j++){
				pros[1-flag][i]+=pros[flag][i-j];
			}
		}
		flag=1-flag;
	}
	
	int total = (int) Math.pow(6, n);
	for(int i=n;i<=6*n;i++){
		System.out.println(i+":"+pros[flag][i]+"/"+total);
	}
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值