@@ -51,51 +51,111 @@ Alice 先开始,只能拿前 5 颗或后 5 颗石子 。
51
51
52
52
<!-- 这里可写通用的实现逻辑 -->
53
53
54
- ** 方法一:动态规划 **
54
+ ** 方法一:记忆化搜索 **
55
55
56
- 设 $dp [ i ] [ j ] $ 表示在石子堆 $ [ i,j ] $ 中,当前玩家与另一个玩家的石子数量的最大差值 。
56
+ 我们设计一个函数 $dfs(i, j)$,表示从第 $i$ 堆石子到第 $j$ 堆石子,当前玩家与另一个玩家的石子数量之差的最大值。那么答案就是 $dfs(0, n - 1) \gt 0$ 。
57
57
58
- 若 $dp [ 0 ] [ n-1 ] \gt 0$,说明当前玩家能赢得比赛。
58
+ 函数 $dfs(i, j)$ 的计算方法如下:
59
59
60
- 时间复杂度 $O(n^2)$,空间复杂度 $O(n^2)$。其中 $n$ 是石子堆的数量。
60
+ - 如果 $i \gt j$,说明当前没有石子了,所以当前玩家没有石子可以拿,差值为 $0$,即 $dfs(i, j) = 0$。
61
+ - 否则,当前玩家有两种选择,如果选择第 $i$ 堆石子,那么当前玩家与另一个玩家的石子数量之差为 $piles[ i] - dfs(i + 1, j)$;如果选择第 $j$ 堆石子,那么当前玩家与另一个玩家的石子数量之差为 $piles[ j] - dfs(i, j - 1)$。当前玩家会选择两种情况中差值较大的情况,也就是说 $dfs(i, j) = \max(piles[ i] - dfs(i + 1, j), piles[ j] - dfs(i, j - 1))$。
62
+
63
+ 最后,我们只需要判断 $dfs(0, n - 1) \gt 0$ 即可。
64
+
65
+ 为了避免重复计算,我们可以使用记忆化搜索的方法,用一个数组 $f$ 记录所有的 $dfs(i, j)$ 的值,当函数再次被调用到时,我们可以直接从 $f$ 中取出答案而不需要重新计算。
66
+
67
+ 时间复杂度 $O(n^2)$,空间复杂度 $O(n^2)$。其中 $n$ 是石子的堆数。
68
+
69
+ ** 方法二:动态规划**
70
+
71
+ 我们也可以使用动态规划的方法,定义 $f[ i] [ j ] $ 表示当前玩家在 $piles[ i..j] $ 这部分石子中能够获得的最大石子数的差值。那么最后答案就是 $f[ 0] [ n - 1 ] \gt 0$。
72
+
73
+ 初始时 $f[ i] [ i ] =piles[ i] $,因为只有一堆石子,所以当前玩家只能拿取这堆石子,差值为 $piles[ i] $。
74
+
75
+ 考虑 $f[ i] [ j ] $,其中 $i \lt j$,有两种情况:
76
+
77
+ - 如果当前玩家拿走了石子堆 $piles[ i] $,那么剩下的石子堆为 $piles[ i + 1..j] $,此时轮到另一个玩家进行游戏,所以 $f[ i] [ j ] = piles[ i] - f[ i + 1] [ j ] $。
78
+ - 如果当前玩家拿走了石子堆 $piles[ j] $,那么剩下的石子堆为 $piles[ i..j - 1] $,此时轮到另一个玩家进行游戏,所以 $f[ i] [ j ] = piles[ j] - f[ i] [ j - 1 ] $。
79
+
80
+ 因此,最终的状态转移方程为 $f[ i] [ j ] = \max(piles[ i] - f[ i + 1] [ j ] , piles[ j] - f[ i] [ j - 1 ] )$。
81
+
82
+ 最后,我们只需要判断 $f[ 0] [ n - 1 ] \gt 0$ 即可。
83
+
84
+ 时间复杂度 $O(n^2)$,空间复杂度 $O(n^2)$。其中 $n$ 是石子的堆数。
61
85
62
86
<!-- tabs:start -->
63
87
64
88
### ** Python3**
65
89
66
90
<!-- 这里可写当前语言的特殊实现逻辑 -->
67
91
92
+ ``` python
93
+ class Solution :
94
+ def stoneGame (self , piles : List[int ]) -> bool :
95
+ @cache
96
+ def dfs (i : int , j : int ) -> int :
97
+ if i > j:
98
+ return 0
99
+ return max (piles[i] - dfs(i + 1 , j), piles[j] - dfs(i, j - 1 ))
100
+
101
+ return dfs(0 , len (piles) - 1 ) > 0
102
+ ```
103
+
68
104
``` python
69
105
class Solution :
70
106
def stoneGame (self , piles : List[int ]) -> bool :
71
107
n = len (piles)
72
- dp = [[0 ] * n for _ in range (n)]
73
- for i, v in enumerate (piles):
74
- dp [i][i] = v
108
+ f = [[0 ] * n for _ in range (n)]
109
+ for i, x in enumerate (piles):
110
+ f [i][i] = x
75
111
for i in range (n - 2 , - 1 , - 1 ):
76
112
for j in range (i + 1 , n):
77
- dp [i][j] = max (piles[i] - dp [i + 1 ][j], piles[j] - dp [i][j - 1 ])
78
- return dp [0 ][- 1 ] > 0
113
+ f [i][j] = max (piles[i] - f [i + 1 ][j], piles[j] - f [i][j - 1 ])
114
+ return f [0 ][n - 1 ] > 0
79
115
```
80
116
81
117
### ** Java**
82
118
83
119
<!-- 这里可写当前语言的特殊实现逻辑 -->
84
120
121
+ ``` java
122
+ class Solution {
123
+ private int [] piles;
124
+ private int [][] f;
125
+
126
+ public boolean stoneGame (int [] piles ) {
127
+ this . piles = piles;
128
+ int n = piles. length;
129
+ f = new int [n][n];
130
+ return dfs(0 , n - 1 ) > 0 ;
131
+ }
132
+
133
+ private int dfs (int i , int j ) {
134
+ if (i > j) {
135
+ return 0 ;
136
+ }
137
+ if (f[i][j] != 0 ) {
138
+ return f[i][j];
139
+ }
140
+ return f[i][j] = Math . max(piles[i] - dfs(i + 1 , j), piles[j] - dfs(i, j - 1 ));
141
+ }
142
+ }
143
+ ```
144
+
85
145
``` java
86
146
class Solution {
87
147
public boolean stoneGame (int [] piles ) {
88
148
int n = piles. length;
89
- int [][] dp = new int [n][n];
149
+ int [][] f = new int [n][n];
90
150
for (int i = 0 ; i < n; ++ i) {
91
- dp [i][i] = piles[i];
151
+ f [i][i] = piles[i];
92
152
}
93
153
for (int i = n - 2 ; i >= 0 ; -- i) {
94
154
for (int j = i + 1 ; j < n; ++ j) {
95
- dp [i][j] = Math . max(piles[i] - dp [i + 1 ][j], piles[j] - dp [i][j - 1 ]);
155
+ f [i][j] = Math . max(piles[i] - f [i + 1 ][j], piles[j] - f [i][j - 1 ]);
96
156
}
97
157
}
98
- return dp [0 ][n - 1 ] > 0 ;
158
+ return f [0 ][n - 1 ] > 0 ;
99
159
}
100
160
}
101
161
```
@@ -107,12 +167,38 @@ class Solution {
107
167
public:
108
168
bool stoneGame(vector<int >& piles) {
109
169
int n = piles.size();
110
- vector<vector<int >> dp(n, vector<int >(n));
111
- for (int i = 0; i < n; ++i) dp[ i] [ i ] = piles[ i] ;
112
- for (int i = n - 2; ~ i; --i)
113
- for (int j = i + 1; j < n; ++j)
114
- dp[ i] [ j ] = max(piles[ i] - dp[ i + 1] [ j ] , piles[ j] - dp[ i] [ j - 1 ] );
115
- return dp[ 0] [ n - 1 ] > 0;
170
+ int f[ n] [ n ] ;
171
+ memset(f, 0, sizeof(f));
172
+ function<int(int, int)> dfs = [ &] (int i, int j) -> int {
173
+ if (i > j) {
174
+ return 0;
175
+ }
176
+ if (f[ i] [ j ] ) {
177
+ return f[ i] [ j ] ;
178
+ }
179
+ return f[ i] [ j ] = max(piles[ i] - dfs(i + 1, j), piles[ j] - dfs(i, j - 1));
180
+ };
181
+ return dfs(0, n - 1) > 0;
182
+ }
183
+ };
184
+ ```
185
+
186
+ ```cpp
187
+ class Solution {
188
+ public:
189
+ bool stoneGame(vector<int>& piles) {
190
+ int n = piles.size();
191
+ int f[n][n];
192
+ memset(f, 0, sizeof(f));
193
+ for (int i = 0; i < n; ++i) {
194
+ f[i][i] = piles[i];
195
+ }
196
+ for (int i = n - 2; ~i; --i) {
197
+ for (int j = i + 1; j < n; ++j) {
198
+ f[i][j] = max(piles[i] - f[i + 1][j], piles[j] - f[i][j - 1]);
199
+ }
200
+ }
201
+ return f[0][n - 1] > 0;
116
202
}
117
203
};
118
204
```
@@ -122,17 +208,45 @@ public:
122
208
``` go
123
209
func stoneGame (piles []int ) bool {
124
210
n := len (piles)
125
- dp := make([][]int, n)
126
- for i, v := range piles {
127
- dp[i] = make([]int, n)
128
- dp[i][i] = v
211
+ f := make ([][]int , n)
212
+ for i := range f {
213
+ f[i] = make ([]int , n)
214
+ }
215
+ var dfs func (i, j int ) int
216
+ dfs = func (i, j int ) int {
217
+ if i > j {
218
+ return 0
219
+ }
220
+ if f[i][j] == 0 {
221
+ f[i][j] = max (piles[i]-dfs (i+1 , j), piles[j]-dfs (i, j-1 ))
222
+ }
223
+ return f[i][j]
224
+ }
225
+ return dfs (0 , n-1 ) > 0
226
+ }
227
+
228
+ func max (a , b int ) int {
229
+ if a > b {
230
+ return a
231
+ }
232
+ return b
233
+ }
234
+ ```
235
+
236
+ ``` go
237
+ func stoneGame (piles []int ) bool {
238
+ n := len (piles)
239
+ f := make ([][]int , n)
240
+ for i , x := range piles {
241
+ f[i] = make ([]int , n)
242
+ f[i][i] = x
129
243
}
130
244
for i := n - 2 ; i >= 0 ; i-- {
131
245
for j := i + 1 ; j < n; j++ {
132
- dp [i][j] = max(piles[i]-dp [i+1][j], piles[j]-dp [i][j-1])
246
+ f [i][j] = max (piles[i]-f [i+1 ][j], piles[j]-f [i][j-1 ])
133
247
}
134
248
}
135
- return dp [0][n-1] > 0
249
+ return f [0 ][n-1 ] > 0
136
250
}
137
251
138
252
func max (a , b int ) int {
@@ -143,6 +257,44 @@ func max(a, b int) int {
143
257
}
144
258
```
145
259
260
+ ### ** TypeScript**
261
+
262
+ ``` ts
263
+ function stoneGame(piles : number []): boolean {
264
+ const n = piles .length ;
265
+ const f: number [][] = new Array (n ).fill (0 ).map (() => new Array (n ).fill (0 ));
266
+ const dfs = (i : number , j : number ): number => {
267
+ if (i > j ) {
268
+ return 0 ;
269
+ }
270
+ if (f [i ][j ] === 0 ) {
271
+ f [i ][j ] = Math .max (
272
+ piles [i ] - dfs (i + 1 , j ),
273
+ piles [j ] - dfs (i , j - 1 ),
274
+ );
275
+ }
276
+ return f [i ][j ];
277
+ };
278
+ return dfs (0 , n - 1 ) > 0 ;
279
+ }
280
+ ```
281
+
282
+ ``` ts
283
+ function stoneGame(piles : number []): boolean {
284
+ const n = piles .length ;
285
+ const f: number [][] = new Array (n ).fill (0 ).map (() => new Array (n ).fill (0 ));
286
+ for (let i = 0 ; i < n ; ++ i ) {
287
+ f [i ][i ] = piles [i ];
288
+ }
289
+ for (let i = n - 2 ; i >= 0 ; -- i ) {
290
+ for (let j = i + 1 ; j < n ; ++ j ) {
291
+ f [i ][j ] = Math .max (piles [i ] - f [i + 1 ][j ], piles [j ] - f [i ][j - 1 ]);
292
+ }
293
+ }
294
+ return f [0 ][n - 1 ] > 0 ;
295
+ }
296
+ ```
297
+
146
298
### ** ...**
147
299
148
300
```
0 commit comments