33
33
34
34
<!-- 这里可写通用的实现逻辑 -->
35
35
36
- 动态规划求解。
36
+ ** 方法一:动态规划 **
37
37
38
- 扔 n 个骰子,点数之和的范围在 ` [n, 6n] ` 之间,总共有 ` 5n+1 ` 种,即为最后结果数组的长度。
38
+ 我们定义 $f [ i ] [ j ] $ 表示投掷 $i$ 个骰子,点数和为 $j$ 的方案数。那么我们可以写出状态转移方程:
39
39
40
- 假设 ` dp[i][j] ` 表示扔 i 个骰子,出现点数之和 j 的次数。n 个骰子,所以 i 的范围在 ` 1~n ` ,j 的范围在 ` [1, 6n] ` 。
40
+ $$
41
+ f[i][j] = \sum_{k=1}^6 f[i-1][j-k]
42
+ $$
41
43
42
- 单看第 n 枚骰子,它的点数可能为 ` 1,2,3,...,6 ` ,因此扔完 n 枚骰子后点数之和 j 出现的次数,可以由扔完 n-1 枚骰子后,对应点数 ` j−1,j−2,j−3,...,j−6 ` 出现的次数之和转化过来。即:
44
+ 其中 $k$ 表示当前骰子的点数,$f [ i-1 ] [ j-k ] $ 表示投掷 $i-1$ 个骰子,点数和为 $j-k$ 的方案数。
43
45
44
- ```
45
- for (第n枚骰子的点数 i = 1; i <= 6; i ++) {
46
- dp[n][j] += dp[n-1][j - i]
47
- }
48
- ```
46
+ 最终我们需要求的是 $f[ n] [ n \sim 6n ] $ 的和,即投掷 $n$ 个骰子,点数和为 $n \sim 6n$ 的方案数之和。
49
47
50
- 扔 1 枚骰子,点数可能是 ` 1,2,3,4,5,6 ` ,且每个点数出现的次数均为 1。所以初始化如下:
48
+ 注意到 $f [ i ] [ j ] $ 的值只与 $f [ i-1 ] [ j-k ] $ 有关,因此我们可以使用滚动数组的方法将空间复杂度降低到 $O(6n)$。
51
49
52
- ```
53
- for (int j = 1; j <= 6; ++j) {
54
- dp[1][j] = 1;
55
- }
56
- ```
50
+ 时间复杂度 $O(n^2)$,空间复杂度 $O(6n)$。其中 $n$ 为骰子个数。
57
51
58
52
<!-- tabs:start -->
59
53
@@ -63,20 +57,32 @@ for (int j = 1; j <= 6; ++j) {
63
57
64
58
``` python
65
59
class Solution :
66
- def twoSum (self , n : int ) -> List[float ]:
67
- dp = [[0 for _ in range (6 * n + 1 )] for _ in range (n + 1 )]
60
+ def dicesProbability (self , n : int ) -> List[float ]:
61
+ f = [[0 ] * (6 * n + 1 ) for _ in range (n + 1 )]
68
62
for j in range (1 , 7 ):
69
- dp[1 ][j] = 1
63
+ f[1 ][j] = 1
64
+ for i in range (2 , n + 1 ):
65
+ for j in range (i, 6 * i + 1 ):
66
+ for k in range (1 , 7 ):
67
+ if j - k >= 0 :
68
+ f[i][j] += f[i - 1 ][j - k]
69
+ m = pow (6 , n)
70
+ return [f[n][i] / m for i in range (n, 6 * n + 1 )]
71
+ ```
72
+
73
+ ``` python
74
+ class Solution :
75
+ def dicesProbability (self , n : int ) -> List[float ]:
76
+ f = [0 ] + [1 ] * 6
70
77
for i in range (2 , n + 1 ):
78
+ g = [0 ] * (6 * i + 1 )
71
79
for j in range (i, 6 * i + 1 ):
72
80
for k in range (1 , 7 ):
73
- if j <= k:
74
- break
75
- dp[i][j] += dp[i - 1 ][j - k]
76
- res, total = [], pow (6 , n)
77
- for i in range (5 * n + 1 ):
78
- res.append(dp[n][n + i] / total)
79
- return res
81
+ if 0 <= j - k < len (f):
82
+ g[j] += f[j - k]
83
+ f = g
84
+ m = pow (6 , n)
85
+ return [f[j] / m for j in range (n, 6 * n + 1 )]
80
86
```
81
87
82
88
### ** Java**
@@ -85,55 +91,88 @@ class Solution:
85
91
86
92
``` java
87
93
class Solution {
88
- public double [] twoSum (int n ) {
89
- int [][] dp = new int [n + 1 ][6 * n + 1 ];
94
+ public double [] dicesProbability (int n ) {
95
+ int [][] f = new int [n + 1 ][6 * n + 1 ];
90
96
for (int j = 1 ; j <= 6 ; ++ j) {
91
- dp [1 ][j] = 1 ;
97
+ f [1 ][j] = 1 ;
92
98
}
93
99
for (int i = 2 ; i <= n; ++ i) {
94
100
for (int j = i; j <= 6 * i; ++ j) {
95
- for (int k = 1 ; k <= 6 && j > k; ++ k) {
96
- dp[i][j] += dp[i - 1 ][j - k];
101
+ for (int k = 1 ; k <= 6 ; ++ k) {
102
+ if (j >= k) {
103
+ f[i][j] += f[i - 1 ][j - k];
104
+ }
97
105
}
98
106
}
99
107
}
100
- double [] res = new double [ 5 * n + 1 ] ;
101
- double all = Math . pow( 6 , n) ;
102
- for (int i = 0 ; i <= 5 * n ; ++ i) {
103
- res [i] = dp [n][n + i] * 1.0 / all ;
108
+ double m = Math . pow( 6 , n) ;
109
+ double [] ans = new double [ 5 * n + 1 ] ;
110
+ for (int i = 0 ; i < ans . length ; ++ i) {
111
+ ans [i] = f [n][n + i] / m ;
104
112
}
105
- return res ;
113
+ return ans ;
106
114
}
107
115
}
108
116
```
109
117
110
- ### ** JavaScript **
118
+ ### ** C++ **
111
119
112
- ``` js
113
- /**
114
- * @param {number} n
115
- * @return {number[]}
116
- */
117
- var twoSum = function (n ) {
118
- function backtrack (sum , time ) {
119
- if (time === n) {
120
- res[sum]++ ;
121
- return ;
120
+ ``` cpp
121
+ class Solution {
122
+ public:
123
+ vector<double > dicesProbability(int n) {
124
+ int f[ n + 1] [ 6 * n + 1 ] ;
125
+ memset(f, 0, sizeof f);
126
+ for (int j = 1; j <= 6; ++j) {
127
+ f[ 1] [ j ] = 1;
122
128
}
123
- for (let i = 1 ; i <= 6 ; i++ ) {
124
- backtrack (sum + i, time + 1 );
129
+ for (int i = 2; i <= n; ++i) {
130
+ for (int j = i; j <= 6 * i; ++j) {
131
+ for (int k = 1; k <= 6; ++k) {
132
+ if (j >= k) {
133
+ f[ i] [ j ] += f[ i - 1] [ j - k ] ;
134
+ }
135
+ }
136
+ }
137
+ }
138
+ vector<double > ans(5 * n + 1);
139
+ double m = pow(6, n);
140
+ for (int i = 0; i < ans.size(); ++i) {
141
+ ans[ i] = f[ n] [ n + i ] / m;
125
142
}
143
+ return ans;
126
144
}
127
- let len = n * 6 ;
128
- let t = 6 ** n;
129
- let res = new Array (len + 1 ).fill (0 );
130
- backtrack (0 , 0 );
131
- return res .slice (n).map (e => e / t);
132
145
};
133
146
```
134
147
135
148
### **Go**
136
149
150
+ ```go
151
+ func dicesProbability(n int) (ans []float64) {
152
+ f := make([][]int, n+1)
153
+ for i := range f {
154
+ f[i] = make([]int, 6*n+1)
155
+ }
156
+ for j := 1; j <= 6; j++ {
157
+ f[1][j] = 1
158
+ }
159
+ for i := 2; i <= n; i++ {
160
+ for j := i; j <= 6*i; j++ {
161
+ for k := 1; k <= 6; k++ {
162
+ if j >= k {
163
+ f[i][j] += f[i-1][j-k]
164
+ }
165
+ }
166
+ }
167
+ }
168
+ m := math.Pow(6, float64(n))
169
+ for j := n; j <= 6*n; j++ {
170
+ ans = append(ans, float64(f[n][j])/m)
171
+ }
172
+ return
173
+ }
174
+ ```
175
+
137
176
``` go
138
177
func dicesProbability (n int ) []float64 {
139
178
dp := make ([]float64 , 7 )
@@ -154,6 +193,36 @@ func dicesProbability(n int) []float64 {
154
193
}
155
194
```
156
195
196
+ ### ** JavaScript**
197
+
198
+ ``` js
199
+ /**
200
+ * @param {number} n
201
+ * @return {number[]}
202
+ */
203
+ var dicesProbability = function (n ) {
204
+ const f = Array .from ({ length: n + 1 }, () => Array (6 * n + 1 ).fill (0 ));
205
+ for (let j = 1 ; j <= 6 ; ++ j) {
206
+ f[1 ][j] = 1 ;
207
+ }
208
+ for (let i = 2 ; i <= n; ++ i) {
209
+ for (let j = i; j <= 6 * i; ++ j) {
210
+ for (let k = 1 ; k <= 6 ; ++ k) {
211
+ if (j >= k) {
212
+ f[i][j] += f[i - 1 ][j - k];
213
+ }
214
+ }
215
+ }
216
+ }
217
+ const ans = [];
218
+ const m = Math .pow (6 , n);
219
+ for (let j = n; j <= 6 * n; ++ j) {
220
+ ans .push (f[n][j] / m);
221
+ }
222
+ return ans;
223
+ };
224
+ ```
225
+
157
226
### ** C#**
158
227
159
228
``` cs
0 commit comments