486. 预测赢家(博弈类DP)(递归 || 动态规划)
算法1:递归
/*
递归:
定义get (int l,int r):先手玩家从数组[l,r]中能够拿取的最大 差值
如果l == r,那么只能拿取nums[l];
如果l < r,那么可以拿取max(nums[l] - get(l +1,r), nums[r] - get(l,r+1))
满足题意只需要 get(0,n) >= 0; 题目规定同分仍是玩家1获胜
时间复杂度O(2 ^ n),空间复杂度O(n)
*/
class Solution {
public:
bool PredictTheWinner(vector<int>& nums) {
int n = nums.size();
return get(nums,0, n - 1) >= 0;
}
int get(vector<int>& nums,int l,int r)
{
if(l == r) return nums[l];
return max(nums[l] - get(nums,l+1,r), nums[r] - get(nums,l,r-1));
}
};
算法2:动态规划
/*
动态规划:
状态表示:
集合:f[l][r]: 从[l,r]中玩家获得分数的 差值
属性:Max
状态计算:
f[l][r] = max(nums[l] - f[l+1][r], nums[r] - f[l][r - 1]) (l < r)
特殊情况:l == r,f[l][r] = nums[l];
时间复杂度O(n ^ 2),空间复杂度O(n ^ 2)
*/
class Solution {
public:
bool PredictTheWinner(vector<int>& nums) {
int n = nums.size();
vector<vector<int>> f(n,vector<int>(n));
for(int i=0;i<n;i++) f[i][i] = nums[i];
for(int l = n - 2; l >= 0 ; l -- ) // 注意这里l是从大到小循环,从小到大会覆盖原来的结果
for(int r = l + 1; r < n ;r ++ )
f[l][r] = max(nums[l] - f[l + 1][r], nums[r] - f[l][r-1]);
return f[0][n - 1] >= 0;
}
};