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;
    }
};
posted @ 2021-06-26 10:46  Dazzling!  阅读(25)  评论(0编辑  收藏  举报