Skip to content

Commit 3fe1c8a

Browse files
committed
n个骰子的点数
1 parent e75078e commit 3fe1c8a

File tree

1 file changed

+150
-0
lines changed

1 file changed

+150
-0
lines changed

n个骰子的点数.md

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# 题目描述
2+
把n个骰子仍在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。
3+
4+
# 测试用例
5+
* 功能测试(1、2、3、4个骰子的各点数的概率)
6+
* 特殊输入测试(输入0)
7+
* 性能测试(输入较大的数字,如11)。
8+
9+
# 题目考点
10+
* 考察应聘者的数学建模能力。
11+
* 考察应聘者对递归和循环的性能的理解。
12+
13+
# 解题思路
14+
用两个数组来存储骰子点数的每个总数出现的次数(动态规划数组)
15+
16+
n个骰子,n轮
17+
18+
在第一轮循环中,第一个数组中的第n个数字表示骰子和为n出现的次数
19+
20+
在下一轮循环中,我们加上一个新的骰子,此时和为n的骰子出现的次数应该等于上一轮循环中骰子点数和为n-1、n-2、n-3、n-4、n-5与n-6的次数的总和
21+
22+
依次类推求解。
23+
# 自己解题
24+
```java
25+
/**
26+
* n个骰子的点数
27+
*
28+
* @Author rex
29+
* 2018/9/18
30+
*/
31+
public class Solution {
32+
/**
33+
* 骰子最大值
34+
*/
35+
int maxValue = 6;
36+
37+
/**
38+
* 递归解法
39+
* @param n
40+
* @return
41+
*/
42+
public List<Map.Entry<Integer, Double>> dicesSum(int n) {
43+
List<Map.Entry<Integer, Double>> result = new ArrayList<AbstractMap.Entry<Integer, Double>>();
44+
if (n <= 0) {
45+
return result;
46+
}
47+
// 结果次数
48+
int[] resultArray = new int[maxValue * n - n + 1];
49+
// 可能情况
50+
int total = (int)Math.pow(maxValue, n);
51+
// 算出次数
52+
probability(n, resultArray);
53+
for (int i = 0; i < resultArray.length; i++) {
54+
result.add(new AbstractMap.SimpleEntry<Integer, Double>(i + n, (double)resultArray[i] / total));
55+
}
56+
return result;
57+
}
58+
59+
/**
60+
* 递归开始
61+
* @param n
62+
* @param resultArray
63+
*/
64+
public void probability(int n, int[] resultArray) {
65+
for (int i = 1; i <= maxValue; i++) {
66+
probability(n, i, n, resultArray);
67+
}
68+
}
69+
70+
/**
71+
* 递归核心
72+
* @param original
73+
* @param sum
74+
* @param current
75+
* @param resultArray
76+
*/
77+
public void probability(int original, int sum, int current, int[] resultArray) {
78+
if (current == 1) {
79+
resultArray[sum - original]++;
80+
} else {
81+
for (int i = 1; i <= maxValue; i++) {
82+
probability(original, sum + i, current - 1, resultArray);
83+
}
84+
}
85+
86+
}
87+
}
88+
```
89+
测试通过率仅为75%,当n大于等于15,超出时间限制。
90+
# 参考解题
91+
```java
92+
/**
93+
* n个骰子的点数
94+
*
95+
* @Author rex
96+
* 2018/9/18
97+
*/
98+
public class Solution1 {
99+
/**
100+
* 骰子最大值
101+
*/
102+
int maxValue = 6;
103+
104+
/**
105+
* 动态规划解题
106+
* @param n
107+
* @return
108+
*/
109+
public List<Map.Entry<Integer, Double>> dicesSum(int n) {
110+
List<Map.Entry<Integer, Double>> result = new ArrayList<AbstractMap.Entry<Integer, Double>>();
111+
if (n <= 0) {
112+
return result;
113+
}
114+
115+
// 这里一定要用long型,不能用int型,数大了之后会造成int型溢出
116+
// 还折腾了一会
117+
long[][] probabilities = new long[2][maxValue * n + 1];
118+
119+
// 数组转换标志
120+
int flag = 0;
121+
122+
// 用第一个骰子初始化数组
123+
for (int i = 1; i <= maxValue; i++) {
124+
probabilities[flag][i] = 1;
125+
}
126+
for (int k = 2; k <= n; k++) {
127+
// 清空不可能出现的位
128+
for (int i = 0; i < k; i++) {
129+
probabilities[1 - flag][i] = 0;
130+
}
131+
for (int i = k; i <= maxValue * k; i++) {
132+
probabilities[1 - flag][i] = 0;
133+
for (int j = 1; j <= i && j <= maxValue; j++) {
134+
probabilities[1 - flag][i] += probabilities[flag][i - j];
135+
}
136+
}
137+
flag = 1 - flag;
138+
139+
}
140+
141+
double total = Math.pow(maxValue, n);
142+
for (int i = n; i <= maxValue * n; i++) {
143+
result.add(new AbstractMap.SimpleEntry<Integer, Double>(i, probabilities[flag][i] / total));
144+
}
145+
return result;
146+
147+
}
148+
}
149+
```
150+
需要注意的一点就是,动态规划数组要用long型,不然会有int型溢出。

0 commit comments

Comments
 (0)