486. 预测赢家
定义二维数组 \(\textit{dp}\),其行数和列数都等于数组的长度,$\textit{dp}[i][j] $表示当数组剩下的部分为下标 \(i\) 到下标 \(j\) 时,即在下标范围 \([i, j]\) 中,当前玩家与另一个玩家的分数之差的最大值,注意当前玩家不一定是先手。
只有当 \(i \le j\) 时,数组剩下的部分才有意义,因此当 \(i>j\) 时,\(\textit{dp}[i][j]=0\)。
当 \(i=j\) 时,只剩一个数字,当前玩家只能拿取这个数字,因此对于所有 \(0 \le i < \textit{nums}.\text{length}\),都有 \(\textit{dp}[i][i]=\textit{nums}[i]\)。
当 \(i<j\) 时,当前玩家可以选择 \(\textit{nums}[i]\) 或 \(\textit{nums}[j]\),然后轮到另一个玩家在数组剩下的部分选取数字。在两种方案中,当前玩家会选择最优的方案,使得自己的分数最大化。因此可以得到如下状态转移方程:
\[\textit{dp}[i][j]=\max(\textit{nums}[i] - \textit{dp}[i + 1][j], \textit{nums}[j] - \textit{dp}[i][j - 1])
\]
最后判断 \(\textit{dp}[0][\textit{nums}.\text{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;
}
};