🔗 题目链接
题目描述
给你一个整数数组 nums
。玩家 1 和玩家 2 基于这个数组设计了一个游戏。
玩家 1 和玩家 2 轮流进行自己的回合,玩家 1 先手。开始时,两个玩家的初始分值都是 0
。每一回合,玩家从数组的任意一端取一个数字(即,nums[0]
或 nums[nums.length - 1]
),取到的数字将会从数组中移除(数组长度减 1
)。玩家选中的数字将会加到他的得分上。当数组中没有剩余数字可取时,游戏结束。
如果玩家 1 能成为赢家,返回 true
。如果两个玩家得分相等,同样认为玩家 1 是游戏的赢家,也返回 true
。你可以假设每个玩家的玩法都会使他的分数最大化。
题目分析
题目有一句”你可以假设每个玩家的玩法都会使他的分数最大化“很关键,说明两个人都是绝对聪明的人,他们的想法都是一样的。
这道题我们发现数组 nums
是不断变化的,所以可以用动态规划的思路来做。
dp[i][j]
表示的在[i, j]
所组成的子数组,先手玩家比后手玩家多得的分数(正数则为多得,负数则为少得),动态规划方程可以表示为:
在[i, j]
数组中,玩家 1 作为先手,有两种选择:
- 选择
nums[i]
,那么剩下的[i+1, j]
则由玩家 2 作为先手来选择- 在
[i+1, j]
中,玩家 2 作为先手会比玩家 1 多得的分数是dp[i+1][j]
- 在
- 选择
nums[j]
,那么剩下的[i, j-1]
则由玩家 2 作为先手来选择- 在
[i, j-1]
中,玩家 2 作为先手会比玩家 1 多得的分数是dp[i][j-1]
- 在
我们假设nums
数组为[1, 5, 8, 3, 5, 2]
,则表示为:
nums | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
值 | 1 | 5 | 8 | 3 | 5 | 2 |
那么,我们可以得到一个 6×6 的二维表格,只需要把表格上半部分填充完整即可。
dp[i][j] | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
0 | 1 | ❓ | ❓ | ❓ | ❓ | ❓ |
1 | - | 5 | ❓ | ❓ | ❓ | ❓ |
2 | - | - | 8 | ❓ | ❓ | ❓ |
3 | - | - | - | 3 | ❓ | ❓ |
4 | - | - | - | - | 5 | ❓ |
5 | - | - | - | - | - | 2 |
首先,我们填充j=1
列,很容易发现,dp[0][1]
的结果是 4。
dp[i][j] | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
0 | 1 | 4 | ❓ | ❓ | ❓ | ❓ |
1 | 5 | ❓ | ❓ | ❓ | ❓ | |
2 | 8 | ❓ | ❓ | ❓ | ||
3 | 3 | ❓ | ❓ | |||
4 | 5 | ❓ | ||||
5 | 2 |
接下来,我们填充j=2
列:
dp[i][j] | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
0 | 1 | 4 | 4 | 1 | ❓ | ❓ |
1 | 5 | 3 | 0 | ❓ | ❓ | |
2 | 8 | 5 | ❓ | ❓ | ||
3 | 3 | ❓ | ❓ | |||
4 | 5 | ❓ | ||||
5 | 2 |
接下来,我们填充j=3
列:
dp[i][j] | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
0 | 1 | 4 | 4 | 1 | ❓ | ❓ |
1 | 5 | 3 | 0 | ❓ | ❓ | |
2 | 8 | 5 | ❓ | ❓ | ||
3 | 3 | ❓ | ❓ | |||
4 | 5 | ❓ | ||||
5 | 2 |
接下来,我们填充j=4
列:
dp[i][j] | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
0 | 1 | 4 | 4 | 1 | 4 | ❓ |
1 | 5 | 3 | 0 | 5 | ❓ | |
2 | 8 | 5 | 6 | ❓ | ||
3 | 3 | 2 | ❓ | |||
4 | 5 | ❓ | ||||
5 | 2 |
最后,,我们填充j=5
列:
dp[i][j] | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
0 | 1 | 4 | 4 | 1 | 4 | 4 |
1 | 5 | 3 | 0 | 5 | -3 | |
2 | 8 | 5 | 6 | 8 | ||
3 | 3 | 2 | 0 | |||
4 | 5 | 3 | ||||
5 | 2 |
最后,我们发现,玩家 1 是胜利的。
题解代码
/**
* @param {number[]} nums
* @return {boolean}
*/
var PredictTheWinner = function (nums) {
const len = nums.length;
const dp = new Array(len);
for (let i = 0; i < len; i++) {
dp[i] = new Array(len);
dp[i][i] = nums[i];
}
for (let j = 1; j < len; j++) {
for (let i = j - 1; i >= 0; i--) {
dp[i][j] = Math.max(nums[i] - dp[i + 1][j], nums[j] - dp[i][j - 1]);
}
}
return dp[0][len - 1] >= 0;
};