LeetCode 486 Predict the Winner 题解

来源:互联网 发布:苹果桌面主题软件 编辑:程序博客网 时间:2024/06/05 05:03

题目简述:给定非负数组nums。有两个玩家,从玩家1开始交替取出一个数并加到他的分数上,取的时候只能取数组剩余的头尾两个数之一。当所有数都被取完时分数高的玩家获胜。求在给定nums的情况下,预测玩家1是否获胜。假设两个玩家每次都会做出最优选择。
输入:非负数组nums。
输出:一个bool值,表示玩家1是否获胜。
示例:对于数组[1,5,2],玩家1必输,因为无论取1还是2,玩家2都会取5而获胜。


题解:
这是一个最大最小策略的博弈问题。考虑使用动态规则求在某个状态下所能获得的分数最大值。记sum(x,y)=yi=xnums[i]表示区间[x,y]的数之和,dp_max(x,y)dp_min(x,y)表示在区间[x,y]通过最优策略所能获得的最大分数和最小分数。
状态转移方程是:

dp_max(i,j)=max(xi+dp_min(i+1,j),xj+dp_min(i,j1))

简单解释一下,对于区间[i,j],都是两种取法,那么就取这两个方法中更高分数的那个。一旦取了一个数,由于对手也会做最优选择,因此你在剩余的区间得到的分数肯定是最小的。
然后根据sum(x,y)=dp_max(x,y)+dp_min(x,y),可以对状态转移方程进行变形,使其不出现dp_min(x,y)
dp_max(i,j)=max(xi+dp_min(i+1,j),xj+dp_min(i,j1))=max(xi+sum(i+1,j)dp_max(i+1,j),xj+sum(i,j1)dp_max(i,j1))=max(sum(i,j)dp_max(i+1,j),sum(i,j)dp_max(i,j1))=sum(i,j)min(dp_max(i+1,j),dp_max(i,j1))

初始状态是dp_max(i,i)=nums[i]
这个状态转移方程显然可以用递推实现,先从区间长度为1的dp_max(i,i)出发,求出区间长度为2的dp_max(i,i+1),依次增加区间长度,直至求目标状态dp_max(0,n1),表示玩家1所能获得的分数最大值,如果它大于或等于总分的一半,则玩家1必胜。

最后进行空间上的优化,注意到求出dp_max(i,j)只需要它上一级的dp_max(i,j1)以及相邻的dp_max(i+1,j),因此可以改二维为一维,只需要求dp的时候从左到右计算即可。新的状态转移方程是:

dp_max(i)=sum(i,i+j)min(dp(i),dp(i+1)),j

算法实现如下,时间复杂度是O(N2),空间复杂度是O(N)。

class Solution {public:    bool PredictTheWinner(vector<int>& nums) {        int dp[21], sum[21];        sum[0] = 0;        for(int i = 0;i < nums.size();i++) {            sum[i+1] = sum[i] + nums[i];            dp[i] = nums[i];        }        for(int i = 1;i < nums.size();i++) {            for(int j = 0;j < nums.size() - i;j++) {                dp[j] = sum[j+i+1] - sum[j] - min(dp[j], dp[j+1]);            }        }        if(2*dp[0] >= sum[nums.size()]) return true;        else return false;    }};
0 0