Skip to content

Commit b23c753

Browse files
committed
feat: add solutions to lc problem: No.0486
No.0486.Predict the Winner
1 parent 0225e23 commit b23c753

File tree

8 files changed

+352
-197
lines changed

8 files changed

+352
-197
lines changed

solution/0400-0499/0486.Predict the Winner/README.md

Lines changed: 165 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,39 @@
4747

4848
**方法一:记忆化搜索**
4949

50-
定义函数 `dfs(i, j)` 表示先手面对数组 `nums[i..j]` 时,能够获得的最大分数
50+
我们设计一个函数 $dfs(i, j)$,表示从第 $i$ 个数到第 $j$ 个数,当前玩家与另一个玩家的得分之差的最大值。那么答案就是 $dfs(0, n - 1) \gt 0$
5151

52-
我们先看后手,后手可能面对的情况有两种,分别是 `nums[i+1..j]``nums[i..j-1]`,获得的最大分数分别为 `dfs(i+1, j)``dfs(i, j-1)`
52+
函数 $dfs(i, j)$ 的计算方法如下:
5353

54-
先手要最大化自己的分数,就要让后手可获得的分数最小,即 `min(dfs(i+1, j), dfs(i, j-1))`。所以先手能获得的分数为 `sum(nums[i..j]) - min(dfs(i+1, j), dfs(i, j-1))`
54+
- 如果 $i \gt j$,说明当前没有数字了,所以当前玩家没有分数可以拿,差值为 $0$,即 $dfs(i, j) = 0$。
55+
- 否则,当前玩家有两种选择,如果选择第 $i$ 个数,那么当前玩家与另一个玩家的得分之差为 $nums[i] - dfs(i + 1, j)$;如果选择第 $j$ 个数,那么当前玩家与另一个玩家的得分之差为 $nums[j] - dfs(i, j - 1)$。当前玩家会选择两种情况中差值较大的情况,也就是说 $dfs(i, j) = \max(nums[i] - dfs(i + 1, j), nums[j] - dfs(i, j - 1))$。
5556

56-
记忆化搜索即可
57+
最后,我们只需要判断 $dfs(0, n - 1) \gt 0$ 即可
5758

58-
时间复杂度 $O(n^2)$,空间复杂度 $O(n^2)$。其中 $n$ 为数组 `nums` 的长度。
59+
为了避免重复计算,我们可以使用记忆化搜索的方法,用一个数组 $f$ 记录所有的 $dfs(i, j)$ 的值,当函数再次被调用到时,我们可以直接从 $f$ 中取出答案而不需要重新计算。
60+
61+
时间复杂度 $O(n^2)$,空间复杂度 $O(n^2)$。其中 $n$ 是数组的长度。
62+
63+
**方法二:动态规划**
64+
65+
我们也可以使用动态规划的方法,定义 $f[i][j]$ 表示当前玩家在 $nums[i..j]$ 这些数字中能够获得的最大得分的差值。那么最后答案就是 $f[0][n - 1] \gt 0$。
66+
67+
初始时 $f[i][i]=nums[i]$,因为只有一个数,所以当前玩家只能拿取这个数,得分差值为 $nums[i]$。
68+
69+
考虑 $f[i][j]$,其中 $i \lt j$,有两种情况:
70+
71+
- 如果当前玩家拿走了 $nums[i]$,那么剩下的数字为 $nums[i + 1..j]$,此时轮到另一个玩家进行游戏,所以 $f[i][j] = nums[i] - f[i + 1][j]$。
72+
- 如果当前玩家拿走了 $nums[j]$,那么剩下的数字为 $nums[i..j - 1]$,此时轮到另一个玩家进行游戏,所以 $f[i][j] = nums[j] - f[i][j - 1]$。
73+
74+
因此,最终的状态转移方程为 $f[i][j] = \max(nums[i] - f[i + 1][j], nums[j] - f[i][j - 1])$。
75+
76+
最后,我们只需要判断 $f[0][n - 1] \gt 0$ 即可。
77+
78+
时间复杂度 $O(n^2)$,空间复杂度 $O(n^2)$。其中 $n$ 是数组的长度。
79+
80+
相似题目:
81+
82+
- [877. 石子游戏](/solution/0800-0899/0877.Stone%20Game/README.md)
5983

6084
<!-- tabs:start -->
6185

@@ -67,14 +91,25 @@
6791
class Solution:
6892
def PredictTheWinner(self, nums: List[int]) -> bool:
6993
@cache
70-
def dfs(i, j):
94+
def dfs(i: int, j: int) -> int:
7195
if i > j:
7296
return 0
73-
a = min(dfs(i + 1, j), dfs(i, j - 1))
74-
return s[j + 1] - s[i] - a
97+
return max(nums[i] - dfs(i + 1, j), nums[j] - dfs(i, j - 1))
7598

76-
s = list(accumulate(nums, initial=0))
77-
return dfs(0, len(nums) - 1) * 2 >= s[-1]
99+
return dfs(0, len(nums) - 1) >= 0
100+
```
101+
102+
```python
103+
class Solution:
104+
def PredictTheWinner(self, nums: List[int]) -> bool:
105+
n = len(nums)
106+
f = [[0] * n for _ in range(n)]
107+
for i, x in enumerate(nums):
108+
f[i][i] = x
109+
for i in range(n - 2, -1, -1):
110+
for j in range(i + 1, n):
111+
f[i][j] = max(nums[i] - f[i + 1][j], nums[j] - f[i][j - 1])
112+
return f[0][n - 1] >= 0
78113
```
79114

80115
### **Java**
@@ -83,52 +118,42 @@ class Solution:
83118

84119
```java
85120
class Solution {
121+
private int[] nums;
122+
private int[][] f;
123+
86124
public boolean PredictTheWinner(int[] nums) {
125+
this.nums = nums;
87126
int n = nums.length;
88-
if ((n & 1) == 0) {
89-
return true;
127+
f = new int[n][n];
128+
return dfs(0, n - 1) >= 0;
129+
}
130+
131+
private int dfs(int i, int j) {
132+
if (i > j) {
133+
return 0;
90134
}
91-
int[] f = new int[n];
92-
for (int i = n - 1; i >= 0; --i) {
93-
f[i] = nums[i];
94-
for (int j = i + 1; j < n; ++j) {
95-
f[j] = Math.max(nums[i] - f[j], nums[j] - f[j - 1]);
96-
}
135+
if (f[i][j] != 0) {
136+
return f[i][j];
97137
}
98-
return f[n - 1] >= 0;
138+
return f[i][j] = Math.max(nums[i] - dfs(i + 1, j), nums[j] - dfs(i, j - 1));
99139
}
100140
}
101141
```
102142

103143
```java
104144
class Solution {
105-
private int[] s;
106-
private int[][] f;
107-
108145
public boolean PredictTheWinner(int[] nums) {
109146
int n = nums.length;
110-
s = new int[n + 1];
147+
int[][] f = new int[n][n];
111148
for (int i = 0; i < n; ++i) {
112-
s[i + 1] = s[i] + nums[i];
113-
}
114-
f = new int[n + 1][n + 1];
115-
for (var e : f) {
116-
Arrays.fill(e, -1);
149+
f[i][i] = nums[i];
117150
}
118-
return dfs(0, n - 1) * 2 >= s[n];
119-
}
120-
121-
private int dfs(int i, int j) {
122-
if (i > j) {
123-
return 0;
124-
}
125-
if (f[i][j] != -1) {
126-
return f[i][j];
151+
for (int i = n - 2; i >= 0; --i) {
152+
for (int j = i + 1; j < n; ++j) {
153+
f[i][j] = Math.max(nums[i] - f[i + 1][j], nums[j] - f[i][j - 1]);
154+
}
127155
}
128-
int a = Math.min(dfs(i + 1, j), dfs(i, j - 1));
129-
int res = s[j + 1] - s[i] - a;
130-
f[i][j] = res;
131-
return res;
156+
return f[0][n - 1] >= 0;
132157
}
133158
}
134159
```
@@ -138,26 +163,40 @@ class Solution {
138163
```cpp
139164
class Solution {
140165
public:
141-
vector<vector<int>> f;
142-
vector<int> s;
166+
bool PredictTheWinner(vector<int>& nums) {
167+
int n = nums.size();
168+
int f[n][n];
169+
memset(f, 0, sizeof(f));
170+
function<int(int, int)> dfs = [&](int i, int j) -> int {
171+
if (i > j) {
172+
return 0;
173+
}
174+
if (f[i][j]) {
175+
return f[i][j];
176+
}
177+
return f[i][j] = max(nums[i] - dfs(i + 1, j), nums[j] - dfs(i, j - 1));
178+
};
179+
return dfs(0, n - 1) >= 0;
180+
}
181+
};
182+
```
143183
184+
```cpp
185+
class Solution {
186+
public:
144187
bool PredictTheWinner(vector<int>& nums) {
145188
int n = nums.size();
146-
s.resize(n + 1);
189+
int f[n][n];
190+
memset(f, 0, sizeof(f));
147191
for (int i = 0; i < n; ++i) {
148-
s[i + 1] = s[i] + nums[i];
192+
f[i][i] = nums[i];
149193
}
150-
f.assign(n + 1, vector<int>(n + 1, -1));
151-
return dfs(0, n - 1) * 2 >= s[n];
152-
}
153-
154-
int dfs(int i, int j) {
155-
if (i > j) return 0;
156-
if (f[i][j] != -1) return f[i][j];
157-
int a = min(dfs(i + 1, j), dfs(i, j - 1));
158-
int res = s[j + 1] - s[i] - a;
159-
f[i][j] = res;
160-
return res;
194+
for (int i = n - 2; ~i; --i) {
195+
for (int j = i + 1; j < n; ++j) {
196+
f[i][j] = max(nums[i] - f[i + 1][j], nums[j] - f[i][j - 1]);
197+
}
198+
}
199+
return f[0][n - 1] >= 0;
161200
}
162201
};
163202
```
@@ -166,41 +205,94 @@ public:
166205

167206
```go
168207
func PredictTheWinner(nums []int) bool {
169-
n := len(nums)
170-
s := make([]int, n+1)
171-
f := make([][]int, n+1)
172-
for i, v := range nums {
173-
s[i+1] = s[i] + v
174-
}
208+
n := len(nums)
209+
f := make([][]int, n)
175210
for i := range f {
176-
f[i] = make([]int, n+1)
177-
for j := range f[i] {
178-
f[i][j] = -1
179-
}
211+
f[i] = make([]int, n)
180212
}
181213
var dfs func(i, j int) int
182214
dfs = func(i, j int) int {
183215
if i > j {
184216
return 0
185217
}
186-
if f[i][j] != -1 {
187-
return f[i][j]
218+
if f[i][j] == 0 {
219+
f[i][j] = max(nums[i]-dfs(i+1, j), nums[j]-dfs(i, j-1))
188220
}
189-
a := min(dfs(i+1, j), dfs(i, j-1))
190-
f[i][j] = s[j+1] - s[i] - a
191221
return f[i][j]
192222
}
193-
return dfs(0, n-1)*2 >= s[n]
223+
return dfs(0, n-1) >= 0
224+
}
225+
226+
func max(a, b int) int {
227+
if a > b {
228+
return a
229+
}
230+
return b
231+
}
232+
```
233+
234+
```go
235+
func PredictTheWinner(nums []int) bool {
236+
n := len(nums)
237+
f := make([][]int, n)
238+
for i, x := range nums {
239+
f[i] = make([]int, n)
240+
f[i][i] = x
241+
}
242+
for i := n - 2; i >= 0; i-- {
243+
for j := i + 1; j < n; j++ {
244+
f[i][j] = max(nums[i]-f[i+1][j], nums[j]-f[i][j-1])
245+
}
246+
}
247+
return f[0][n-1] >= 0
194248
}
195249

196-
func min(a, b int) int {
197-
if a < b {
250+
func max(a, b int) int {
251+
if a > b {
198252
return a
199253
}
200254
return b
201255
}
202256
```
203257

258+
### **TypeScript**
259+
260+
```ts
261+
function PredictTheWinner(nums: number[]): boolean {
262+
const n = nums.length;
263+
const f: number[][] = new Array(n).fill(0).map(() => new Array(n).fill(0));
264+
const dfs = (i: number, j: number): number => {
265+
if (i > j) {
266+
return 0;
267+
}
268+
if (f[i][j] === 0) {
269+
f[i][j] = Math.max(
270+
nums[i] - dfs(i + 1, j),
271+
nums[j] - dfs(i, j - 1),
272+
);
273+
}
274+
return f[i][j];
275+
};
276+
return dfs(0, n - 1) >= 0;
277+
}
278+
```
279+
280+
```ts
281+
function PredictTheWinner(nums: number[]): boolean {
282+
const n = nums.length;
283+
const f: number[][] = new Array(n).fill(0).map(() => new Array(n).fill(0));
284+
for (let i = 0; i < n; ++i) {
285+
f[i][i] = nums[i];
286+
}
287+
for (let i = n - 2; i >= 0; --i) {
288+
for (let j = i + 1; j < n; ++j) {
289+
f[i][j] = Math.max(nums[i] - f[i + 1][j], nums[j] - f[i][j - 1]);
290+
}
291+
}
292+
return f[0][n - 1] >= 0;
293+
}
294+
```
295+
204296
### **...**
205297

206298
```

0 commit comments

Comments
 (0)