394. Coins in a Line
Tag:
Dynamic Problem
Main Idea:
DP-Game Problem. This problem can have multiple solutions.
Solution 1:
Assuming player A is the first one to take the coins. Let represent player A win/lose. If player A has coins to to take, it means the other player B may have coins to take. If player B chooses , then A need to consider whether ; If player B chooses , then A need to consider whether . Thus, the update equation would be: KaTeX parse error: Expected 'EOF', got '&' at position 20: …[i] = (dp[i-2] &̲& dp[i-3]) || d…. For initialization, . The answer is .
Solution 2:
Let represent win/lose when there has i coins left. As long as , then wins. Thus, the update equation would be: , if . For initialization, . The answer is .
Tips/Notes:
For optimization, this problem can apply rolling array to reduce space cost to
Time/Space Cost:
Time Cost:
Space Cost:
Code:
The code here implement Solution1 without optimization.
class Solution {
public:
/**
* @param n: An integer
* @return: A boolean which equals to true if the first player will win
*/
bool firstWillWin(int n) {
// write your code here
vector<bool> dp(n + 1, false);
dp[0] = false;
dp[1] = true;
dp[2] = true;
dp[3] = false;
for(int i = 4; i <= n; i++){
dp[i] = (dp[i-2] && dp[i-3]) || (dp[i-4] && dp[i-3]);
}
return dp[n];
}
};
Follow-up Problem: 395. Coins in a Line II
Main Idea:
Main idea:
Rolling Array DP Problem. Let dp[i] represents the maximum value player can get, sum[i] represent the sum value of coin from i to n-1. In this case, the maximum value player B can get is sum[i]-dp[i] .
Now, let’s discuss the update equation of dp[i] . There will be two cases: the first is player A takes coin[i] ,then the A can get values[i] + sum[i+1] - dp[i+1] ; The other case is that A takes coin[i] + coin[i+1] ,then the A can get values[i] + values[i+1] + sum[i+2] - dp[i+2] . Thus, the update equation would be: dp[i] = max(values[i] + sum[i+1] - dp[i+1], values[i] + values[i+1] + sum[i+2] - dp[i+2]) .
As for initialization, this DP problem is from back to end. Thus, IF n<3 , return true. ELSE, dp[n-1] = sum[n-1] = values[n-1], dp[n-2] = sum[n-2] = values[n-2] + values[n-1] .
The answer is dp[0] > sum[0] - dp[0] .
For optimization, we only need ***sum[i+1]/sum[i+2], dp[i+1]/dp[i+2]***. Thus, we can implement rolling array to save space cost.
Tips/Notes:
Time/Space Cost:
Time Cost:
Space Cost:
,
if optimize.
Code:
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 < 3){
return true;
}
vector<int> dp(n,0), sum(n, 0);
dp[n-1] = sum[n-1] = values[n-1];
dp[n-2] = sum[n-2] = values[n-2] + values[n-1];
for(int i = n-3; i >= 0; i--){
sum[i] = sum[i+1] + values[i];
dp[i] = max(values[i] + sum[i+1] - dp[i+1],
values[i] + values[i+1] + sum[i+2] - dp[i+2]);
}
return dp[0] > sum[0] - dp[0];
}
};
Follow-up Problem3: 396. Coins in a Line III
Main Idea:
-
State:
dp[i][j] represents the first player A can get the maximum values from i to j. -
Update Function:
There will be two cases: A takes the most left one or the most right one.
-1. A takes the most left one (i), then left (i+1, j) to player B: Left = min(dp[i+2][j], dp[i+1][j-1]) + values[i] .
-2. A takes the most right one (j), then left (i, j-1) to player B: Left = min(dp[i+1][j-1], dp[i][j-2]) + values[j] .
-3. dp[i][j] = max(left, right) -
Initialization:
-1. if x > y, dp[x][y] = 0;
-2. if x = y, dp[x][y] = values[x];
-3. if x + 1 = y, dp[x][y] = max(values[x], values[y]); -
Answer:
Check if the dp[0][n-1] larger than the half of the sum.
Tips/Notes:
- Note the parameter in helper function. Vector should pass pointer.
Time/Space Cost:
Time Cost:
Space Cost:
Code:
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();
vector<vector<int>> dp(n+1, vector<int>(n+1, -1));
int sum = 0;
for(auto now : values){
sum += now;
}
return sum < 2 * search(values, dp, 0, n-1);
}
int search(vector<int> &values, vector<vector<int>> &dp, int x, int y){
if(dp[x][y] >= 0){
return dp[x][y];
}
if(x > y){
dp[x][y] = 0;
}
else if(x == y){
dp[x][y] = values[x];
}
else if(x + 1 == y){
dp[x][y] = max(values[x], values[y]);
}
else{
int left = values[x] + min(search(values, dp, x+2, y), search(values, dp, x+1, y-1));
int right = values[y] + min(search(values, dp, x+1, y-1), search(values, dp, x, y-2));
dp[x][y] = max(left, right);
}
return dp[x][y];
}
};