题目描述:

给定一个表示分数的非负整数数组。 玩家1从数组任意一端拿取一个分数,随后玩家2继续从剩余数组任意一端拿取分数,然后玩家1拿,……。每次一个玩家只能拿取一个分数,分数被拿取之后不再可取。直到没有剩余分数可取时游戏结束。最终获得分数总和最多的玩家获胜。

给定一个表示分数的数组,预测玩家1是否会成为赢家。你可以假设每个玩家的玩法都会使他的分数最大化。

示例1:

输入: [1, 5, 2]
输出: False
解释: 一开始,玩家1可以从1和2中进行选择。
如果他选择2(或者1),那么玩家2可以从1(或者2)和5中进行选择。如果玩家2选择了5,那么玩家1则只剩下1(或者2)可选。
所以,玩家1的最终分数为 1 + 2 = 3,而玩家2为 5。
因此,玩家1永远不会成为赢家,返回 False。

示例2:

输入: [1, 5, 233, 7]
输出: True
解释: 玩家1一开始选择1。然后玩家2必须从5和7中进行选择。无论玩家2选择了哪个,玩家1都可以选择233。
最终,玩家1(234分)比玩家2(12分)获得更多的分数,所以返回 True,表示玩家1可以成为赢家。

注意:

  1. 1 <= 给定的数组长度 <= 20.
  2. 数组里所有分数都为非负数且不会大于10000000。
  3. 如果最终两个玩家的分数相等,那么玩家1仍为赢家。

解析:

对于偶数个数字的数组,玩家1一定获胜。因为一定能找到一个最优的方法使自己赢,如果输了那就不是最优的方法,那就按玩家2的方法拿,如果还输,那就再把玩家2的方法拿来用,每个玩家都足够聪明,所以玩家1一定能找到一个最优的拿法使自己赢

对于奇数个数字的数组,利用动态规划(dynamic programming)计算。 首先证明最优子结构性质。对于数组[0..n-1]中的子数组[i..j],假设玩家1在子数组[i..j]中的拿法是最优的,即拿的分数比玩家2多出最多。假设玩家1拿了i,则[i+1..j]中玩家1拿的方法也一定是最优的。利用反证法证明:如果玩家1在[i+1..j]中有更优的拿法,即玩家1在[i+1...j]可以拿到更多的分数,则玩家在[i..j]中拿到的分数就会比假设的最优拿法拿到的分数更多,显然矛盾。如果玩家1拿了j,同理可证矛盾。 所以当前问题的最优解包含的子问题的解一定也是子问题的最优解。

定义dp[i][j]为在数组[i,j]中先手比后手多拿的最大分数。这里开始时先手是玩家1,若他先拿左边的nums[i]分数,在余下数组[i+1,j]中,玩家2就为先手了,玩家2与玩家1一样聪明,所以在剩余的[i+1,j]数组中,

玩家2比玩家1要多dp[i+1][j]分,同理,玩家1先拿右边的nums[j]分数,那玩家2要比玩家1在数组[i,j-1]中多拿dp[i][j-1]分,玩家1只有这两种从两端拿的情况,所以玩家1(先手)在数组[i.j]中要比玩家2多拿(nums[i]-dp[i+1][j])或者

(nums[j]-dp[i][j-1])分,再看dp[i][j]的定义,则得出这个公式:dp[i][j]=max(nums[i]-dp[i+1][j],nums[j]-dp[i][j-1])

我们在看i,j的取值,我们所要求的结果是dp[0][n-1],为了方便n个数从左到右位置是0,1,2,...n-1。只要dp[0][n-1]大于等于零,就表示玩家1比玩家2的多拿的分数多。要求dp[0][n-1],就要知道dp[1][n-1]与dp[0][n-2]的取值。一种遍历方法是先取最后两个的值,再逐个往前增加元素,例如4个数[0,1,2,3],先求dp[2][3],再求dp[1][2],dp[1][3],之后dp[1][3]=max(1-dp[2][3],3-dp[1][2]).在之后就接着求dp[0][1],dp[0][2],dp[0][3],结果dp[0][3]=max(0-dp[1][3],3-dp[0][2]),等式右边都是已知数。

代码:

class Solution:

    def PredictTheWinner2(self, nums):
        n = len(nums)
        if n % 2 == 0 or n == 1:
            return True
        dp = [[0] * n for _ in range(n)]
        for i in reversed(range(n)):
            for j in range(i+1, n):
                #print(i,j)
                dp[i][j] = max(nums[i] - dp[i+1][j], nums[j] - dp[i][j-1])

        return dp[0][-1] >= 0

大佬链接:https://leetcode-cn.com/problems/predict-the-winner/solution/python-dong-tai-gui-hua-by-zhuhh/

     https://leetcode-cn.com/problems/predict-the-winner/comments/78786

05-18 17:52