描述
有 n 个不同价值的硬币排成一条线。两个参赛者轮流从 左边 依次拿走 1 或 2 个硬币,直到没有硬币为止。计算两个人分别拿到的硬币总价值,价值高的人获胜。
请判定 先手玩家 必胜还是必败?
若必胜, 返回 true, 否则返回 false.
样例
样例 1:
输入: [1, 2, 2]
输出: true
解释: 先手玩家直接拿走两颗硬币即可.
样例 2:
输入: [1, 2, 4]
输出: false
解释: 无论先手拿一个还是两个, 后手可以拿完, 然后总价值更高.
思路
设dpi表示从i到n-1处,先手比后手多拿的分数。那么要求的就是dp0的正负。
因为只可以拿1个或者2个,所以最后的2个dpn-1 = values[n-1], dpn-2 = values[n-1]+values[n-2].
对于任意的dpi,也是只有2个取法:
拿1个values[i]时,先手获得了values[i],但是对于剩下的,他失去了先手,对面的先手获得了dpi+1,所以他比对面多values[i]-dpi+1
拿2个,values[i]和values[i+1]时,先手获得了values[i]+values[i+1],对面的先手可以获得dpi+2,所以此时先手比对面多values[i]+values[i+2]-dpi+2
最终可以从n-3计算到0,得到正负。
代码
class Solution {
public:
/**
* @param values: a vector of integers
* @return: a boolean which equals to true if the first player will win
*/
bool firstWillWin(vector<int> &values) {
// write your code here
int n = values.size();
if (n <= 1) return true;
vector<int> dp;
dp.resize(n,0);
dp[n-1] = values[n-1];
dp[n-2] = values[n-1] + values[n-2];
for (int i = n-3; i >= 0; i--) {
dp[i] = max(values[i] - dp[i+1], values[i]+values[i+1]-dp[i+2]);
}
return dp[0] > 0;
}
};