我好菜,题做得太少了,思维的东西不够。
这道题第一眼我以为是dp,但是它有两个人,好像不满足无后效性,之后又以为是博弈论,但是它又不像取石子有必败态。又觉得这道题数据范围才20,它肯定是想让我们暴搜,但是暴搜我不会写TvT
看了题解,可以递归也可以dp…
方法一:递归
就比较直观,但是要注意这里用turn将玩家二的得分记为负数,就不用再传一个变量了,之后比较大小的时候也要注意正数和负数的问题。
class Solution {
public:
int predict(vector<int>& nums, int turn, int head, int tail)
{
if (head == tail) return nums[head] * turn;
int headScore = nums[head] * turn + predict(nums, turn * (-1), head + 1, tail);
int tailScore = nums[tail] * turn + predict(nums, turn * (-1), head, tail - 1);
return max(headScore * turn, tailScore * turn) * turn;
}
bool PredictTheWinner(vector<int>& nums) {
return predict(nums, 1, 0, nums.size() - 1) >= 0;
}
};
方法二:dp
这种序列取两段的数的问题,感觉一般会用到区间[l, r],每个状态都可以表示为这样一个区间
用dp[l][r]
表示剩余的数是从第l个到第r个的时候,当前走棋的玩家与对面玩家的分差最大值。
dp[l][r] = max(nums[l] - dp[l + 1][r], nums[r] - dp[l][r - 1])
这个状态转移方程式里的减号是灵魂,用一个减号完成了换玩家。