Coins in a Line I/II/III

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   d p [ i ] \ dp[i] represent player A win/lose. If player A has   i \ i coins to to take, it means the other player B may have   i 1 / i 2 \ i-1/i-2 coins to take. If player B chooses   i 1 \ i-1 , then A need to consider whether   i 3 / i 2 \ i-3/i-2 ; If player B chooses   i 2 \ i-2 , then A need to consider whether   i 3 / i 4 \ i-3/i-4 . 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,   d p [ 0 ] = d p [ 3 ] = f a l s e , d p [ 1 ] = d p [ 2 ] = t r u e \ dp[0] = dp[3] = false, dp[1] = dp[2] =true . The answer is   d p [ n ] \ dp[n] .

Solution 2:

Let   d p [ i ] \ dp[i] represent win/lose when there has i coins left. As long as   d p [ i 1 ] = f a l s e d p [ i 2 ] = f a l s e \ dp[i-1]=false || dp[i-2]=false , then   d p [ i ] \ dp[i] wins. Thus, the update equation would be:   d p [ i ] = t r u e \ dp[i] = true , if   d p [ i 1 ] = f a l s e d p [ i 2 ] = f a l s e \ dp[i-1]=false || dp[i-2]=false . For initialization,   d p [ 0 ] = f a l s e , d p [ 1 ] = d p [ 2 ] = t r u e \ dp[0] = false, dp[1] = dp[2] =true . The answer is   d p [ n ] \ dp[n] .

Tips/Notes:
For optimization, this problem can apply rolling array to reduce space cost to   O ( 1 ) \ O(1)

Time/Space Cost:

Time Cost:   O ( n ) \ O(n)
Space Cost:   O ( n ) \ O(n)

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] .

扫描二维码关注公众号,回复: 8641256 查看本文章

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:   O ( n ) \ O(n)
Space Cost:   O ( 2 n ) \ O(2n) ,   O ( 1 ) \ O(1) 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:

  1. Note the parameter in helper function. Vector should pass pointer.

Time/Space Cost:

Time Cost:   O ( n 2 ) \ O(n^2)
Space Cost:   O ( n 2 ) \ O(n^2)

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];
    }
};
发布了10 篇原创文章 · 获赞 0 · 访问量 101

猜你喜欢

转载自blog.csdn.net/Zahb44856/article/details/103910332
今日推荐