here are n coins with different value in a line. Two players take turns to take one or two coins from left side until there are no more coins left. The player who take the coins with the most value wins.
Could you please decide the first player will win or lose?
Given values array A = [1,2,2]
, return true
.
Given A = [1,2,4]
, return false
.
Coins in a Line 三部曲的第二部,也是道博弈类的DP。这类问题每次定义一个人的状态。比如这题我们定义f[i]为还剩i枚硬币时先手取硬币的人获得的最大价值。这里从左朝右走,所以还剩i枚是从右往左走的。我们求的最终状态是还剩n枚硬币时先手的状态(也就是真正对应第一个取硬币的人)。注意这里定义状态里的先手并不一定是我们题意所说的游戏开始的先手,题目中的先手是f[n]时的先手,而在f[i]时的先手仅仅是在还剩i枚硬币时第一个取硬币的人,可以是player A, 也可以是player B。
考虑转移方程,还剩i枚硬币时的状态,可以通过从左边取1枚或者2枚到达f[i-1],f[i-2]。 当然这个取硬币的人是f[i]中的先手,f[i-1],f[i-2]中的后手。所以转换方程是
f[i] = sum[i] - min(f[i-1],f[i-2])
初始化状态,当还剩0枚硬币时,先手获得的最大价值是0,还剩1枚时,f[1] = values[-1], 还剩2枚时,f[2] = values[-1]+values[-2].
最后取值是f[n]*2 > sum[n]
这题要相当注意初始化的处理,代码如下:
class Solution: # @param values: a list of integers # @return: a boolean which equals to True if the first player will win def firstWillWin(self, values): if not values: return 0 if len(values) < 2: return True dp = [0] * (len(values) + 1) #while the i coins left, the first player's #most value, i is from right to left dp[1] = values[-1] dp[2] = values[-1] + values[-2] sums = [values[-1]] for i in xrange(len(values) - 2, -1, -1): #from right to left sums.append(sums[-1] + values[i]) for i in xrange(3,len(values) + 1): dp[i] = sums[i-1] - min(dp[i-2],dp[i-1]) return dp[len(values)]*2 > sums[len(values)-1]
这题需要用到求和来做推演,所以最好的方式是预先求出来,prefixsum的形式,空间和时间复杂度都是O(n).