定义二维数组 ( extit{dp}),其行数和列数都等于数组的长度,$ extit{dp}[i][j] $表示当数组剩下的部分为下标 (i) 到下标 (j) 时,即在下标范围 ([i, j]) 中,当前玩家与另一个玩家的分数之差的最大值,注意当前玩家不一定是先手。
只有当 (i le j) 时,数组剩下的部分才有意义,因此当 (i>j) 时,( extit{dp}[i][j]=0)。
当 (i=j) 时,只剩一个数字,当前玩家只能拿取这个数字,因此对于所有 (0 le i < extit{nums}. ext{length}),都有 ( extit{dp}[i][i]= extit{nums}[i])。
当 (i<j) 时,当前玩家可以选择 ( extit{nums}[i]) 或 ( extit{nums}[j]),然后轮到另一个玩家在数组剩下的部分选取数字。在两种方案中,当前玩家会选择最优的方案,使得自己的分数最大化。因此可以得到如下状态转移方程:
[ extit{dp}[i][j]=max( extit{nums}[i] - extit{dp}[i + 1][j], extit{nums}[j] - extit{dp}[i][j - 1])
]
最后判断 ( extit{dp}[0][ extit{nums}. ext{length}-1]) 的值,如果大于或等于 (0),则先手得分大于或等于后手得分,因此先手成为赢家,否则后手成为赢家。
class Solution {
public:
bool PredictTheWinner(vector<int>& nums) {
int n = nums.size();
vector<vector<int>> f(n + 1, vector<int>(n));
for(int i = n - 1; i >= 0; i--)
for(int j = i; j < n; j++)
if(i == j) f[i][j] = nums[i];
else f[i][j] = max(nums[i] - f[i + 1][j], nums[j] - f[i][j - 1]);
return f[0][n - 1] >= 0;
}
};