Typical game theory question.
In dp solution, their solution is the same. However before introducing the dp solution, we have a look at the greedy solution of Stone Game.
Greedy solution of Stone Game
If piles' index started with 1, we label all the odd indices black and even indices white. The first player can either choose all white or all black, thus when you know the sum of black and white, as the first player you can always win the game, when the length of the piles is even number.
DP solution:
- dp[left][right] = the interval from left to right, the difference of scores of two player
- both players are smart always choose the best one the maximize the difference
- we update the state from smallest interval to the biggest interval, the correctness got guaranteed, as we found all the combination and keep the smallest one, to get the at least answer. "at least" means in the worst situation the first player would higher or lower than the second player
- About transfer, [left, left + 1, left + 2.......right - 2, right - 1, right], just a simple simulation, if you choose nums[left] than you inheriate the state of dp[left + 1][right], other wise dp[left][right - 1], just a simulation of the original game, dont dig too much here, that's meaningless, in dp we just needed to solve the edge case and consider the smallest problem, pass the answer to bigger problem.
So, we have, dp[i][j] = max(nums[left] - dp[left + 1][right], nums[right] - dp[left][right - 1])
since the state represent the "difference", dp[left + 1][right] and dp[left][right - 1] are opponents turn, you need to deduct this to get how many scores you are heading over or loss behind.
Code:
Stone Game
class Solution {
public:
bool stoneGame(vector<int>& piles) {
int dp[510][510];
for(int i = 0; i < piles.size(); i++)dp[i][i] = piles[i];
for(int len = 2; len <= piles.size(); len++){
for(int i = 0; i < piles.size() - len; i++){
int j = i + len - 1;
dp[i][j] = max(piles[i] - dp[i + 1][j], piles[j] - dp[i][j - 1]);
}
}
return dp[0][piles.size() - 1] >= 0;
}
};
Predict the winner:
class Solution {
public:
bool PredictTheWinner(vector<int>& nums) {
int dp[26][26], n = nums.size();
memset(dp, 0, sizeof(dp));
for(int i = 0; i < n; i++)dp[i][i] = nums[i];
for(int len = 2; len <= n; len++){
for(int lft = 0; lft <= n - len; lft++){
int rght = lft + len - 1;
dp[lft][rght] = max(nums[lft] - dp[lft + 1][rght], nums[rght] - dp[lft][rght - 1]);
}
}
return dp[0][n - 1] >= 0;
}
};