486. Predict the Winner
问题
给定一系列非负的整数,两个玩家轮流从头部或尾部取数,两人都以最优策略玩,问先取数的玩家是否获胜。
Input: [1, 5, 2]
Output: False
思路
这道题跟877. Stone Game一样,只不过没有了几个先验条件,这道题是Stone Game更一般的场景,这道题的代码可以直接过Stone Game。
上次(Stone Game)的dp解法中用双方博弈的思路,有两条公式。其实直接一条公式就可以了。
如果dp[i][j]表示自己取石头,能够获得的比对方多的价值。
那dp[i+1][j]和dp[i][j+1]就是对方取石头,能够获得比自己多的价值。
dp公式为:\(dp[i][j] = max(nums[i] - dp[i+1][j], nums[j] - dp[i][j-1])\)
dp值取决于左方值和下方值,dp矩阵的遍历有几种方式,可以按对角线遍历;也可以按行(先遍历完一行),从下往上遍历;还可以按列(先遍历完一列)。
三种遍历都可以优化成一维数组,如下图所示。
(1)按对角线遍历,遍历完一个对角线,再往右上角的另一个对角线遍历,可以覆盖前一个对角线
(2)按行遍历,遍历完一行,再向上一行遍历,可以覆盖下一行
(3)按列遍历,遍历完一列,再向右一列遍历,可以覆盖前一列
时间复杂度O(n^2),空间复杂度O(n)
代码
Stone Game里我使用的是按对角线遍历的代码,这里我用的是按行遍历的代码。
class Solution(object):
def PredictTheWinner(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
dp = [0 for _ in range(len(nums))]
for i in range(len(nums)-1)[::-1]:
for j in range(i+1, len(nums)):
dp[j] = max(nums[i] - dp[j], nums[j] - dp[j-1])
return dp[len(nums)-1]>=0