Skip to content

Commit 0225e23

Browse files
committed
feat: add solutions to lc problem: No.0877
No.0877.Stone Game
1 parent 43db79d commit 0225e23

File tree

7 files changed

+365
-67
lines changed

7 files changed

+365
-67
lines changed

solution/0800-0899/0877.Stone Game/README.md

Lines changed: 177 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -51,51 +51,111 @@ Alice 先开始,只能拿前 5 颗或后 5 颗石子 。
5151

5252
<!-- 这里可写通用的实现逻辑 -->
5353

54-
**方法一:动态规划**
54+
**方法一:记忆化搜索**
5555

56-
设 $dp[i][j]$ 表示在石子堆 $[i,j]$ 中,当前玩家与另一个玩家的石子数量的最大差值
56+
我们设计一个函数 $dfs(i, j)$,表示从第 $i$ 堆石子到第 $j$ 堆石子,当前玩家与另一个玩家的石子数量之差的最大值。那么答案就是 $dfs(0, n - 1) \gt 0$
5757

58-
若 $dp[0][n-1] \gt 0$,说明当前玩家能赢得比赛。
58+
函数 $dfs(i, j)$ 的计算方法如下:
5959

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$ 是石子的堆数。
6185

6286
<!-- tabs:start -->
6387

6488
### **Python3**
6589

6690
<!-- 这里可写当前语言的特殊实现逻辑 -->
6791

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+
68104
```python
69105
class Solution:
70106
def stoneGame(self, piles: List[int]) -> bool:
71107
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
75111
for i in range(n - 2, -1, -1):
76112
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
79115
```
80116

81117
### **Java**
82118

83119
<!-- 这里可写当前语言的特殊实现逻辑 -->
84120

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+
85145
```java
86146
class Solution {
87147
public boolean stoneGame(int[] piles) {
88148
int n = piles.length;
89-
int[][] dp = new int[n][n];
149+
int[][] f = new int[n][n];
90150
for (int i = 0; i < n; ++i) {
91-
dp[i][i] = piles[i];
151+
f[i][i] = piles[i];
92152
}
93153
for (int i = n - 2; i >= 0; --i) {
94154
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]);
96156
}
97157
}
98-
return dp[0][n - 1] > 0;
158+
return f[0][n - 1] > 0;
99159
}
100160
}
101161
```
@@ -107,12 +167,38 @@ class Solution {
107167
public:
108168
bool stoneGame(vector<int>& piles) {
109169
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;
116202
}
117203
};
118204
```
@@ -122,17 +208,45 @@ public:
122208
```go
123209
func stoneGame(piles []int) bool {
124210
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
129243
}
130244
for i := n - 2; i >= 0; i-- {
131245
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])
133247
}
134248
}
135-
return dp[0][n-1] > 0
249+
return f[0][n-1] > 0
136250
}
137251

138252
func max(a, b int) int {
@@ -143,6 +257,44 @@ func max(a, b int) int {
143257
}
144258
```
145259

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+
146298
### **...**
147299

148300
```

0 commit comments

Comments
 (0)