60 Questions Learning Dynamic Programming Series: Dynamic Programming Algorithm Lecture 4

Dynamic programming problems related to buying and selling stocks

Article Directory

  • 1. The best time to buy and sell stocks includes a freezing period
  • 2. The best time to buy and sell stocks includes handling fees
  • 3. The best time to buy and sell stocks III
  • 4. The best time to buy and sell stocks IV


1. The best time to buy and sell stocks includes a freezing period

Ritko Link: Rikko

Given an array of integers prices, where the th   represents   the stock price on the th day.  prices[i]i

Design an algorithm to calculate the maximum profit. You can complete as many transactions as possible (buy and sell a stock multiple times) subject to the following constraints:

After selling the stock, you cannot buy the stock the next day (that is, the freezing period is 1 day).

Note: You cannot participate in multiple transactions at the same time (you must sell the previous stock before buying again).

 First of all, let's analyze the title. The main point in the title is that you cannot buy the stock the next day after you sell it, and you must sell the original stock before buying a new stock. With this restriction, we can easily analyze the This question is a multi-state dp.

1. Status representation

When we use dp[i] to represent the maximum profit at the end of the i-th day, we find that it is impossible to write the state transition equation, because the maximum profit of the i-th day is required, we need to see whether the i-th day is a freezing period or whether there is no stock in hand Or there are stocks in hand, so we will have three state representations:

f[i] indicates the maximum profit of the stock in hand on the i-th day

g[i] represents the maximum profit without stocks in the i-th day

s[i] represents the maximum profit in the freezing period on day i

2. State transition equation

First of all, we have to analyze each state. For example, if we hold stocks on the i-th day, from which state can we get to the state of having stocks? When there were stocks on the previous day, that is, day i-1, we did nothing and still had stocks on the i-th day. The current day is a state of no stocks, then we bought stocks on the previous day and we will be in the state of stocks on the i-th day.

所以f[i] = max(f[i-1],g[i-1] - p[i])

Next, we analyze the state of no stock. First of all, if there is no stock the day before, then we will still be in the state of no stock after doing nothing until the i-th day. If the previous day was a freezing period, then you will automatically be in a state of no stock after doing nothing until the i-th day (because the stock must be sold during the freezing period, and once you sell it, you will have no stock in your hand).

Because g[i] = max(g[i-1],s[i-1])

Next, let’s analyze the freezing period. The freezing period must be when stocks are sold. Therefore, if there is a stock status the day before, and then the stock is sold, the i-th day is the freezing period.

Because s[i] = f[i-1] + p[i];

3. Initialization

From the state transition equation, we can see that every time the profit of the previous day is needed, only the first day will cross the boundary, so we directly initialize the first day of the three tables. If there are stocks on the first day, then you have to buy, buy The profit becomes negative from 0, so f[0] = -p[0]

If there is no stock on the first day, you can just do nothing, so g[0] = 0

The first day is in the freezing period, so the profit must be 0, so s[0] = 0

4. Fill in the form

From left to right, fill in the three forms together

5. Return value

Returns the maximum value of the last day of the three tables.

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        vector<int> f(n,0),g(n,0),s(n,0);
        f[0] = -prices[0];
        for (int i = 1;i<n;i++)
        {
            f[i] = max(f[i-1],g[i-1]-prices[i]);
            g[i] = max(g[i-1],s[i-1]);
            s[i] = f[i-1]+prices[i];
        }
        return max(f[n-1],max(g[n-1],s[n-1]));
    }
};

Of course, we can also optimize the code. If there are still stocks in the hand that have not been sold on the last day, then the profit on this day must be lower than that in the state of no stock and the state of freezing period, so we only need to return to the state of selling stocks The maximum value is enough:

Of course, it is redundant to use three one-dimensional arrays to represent the state above. We can use two-dimensional arrays to represent the state. The code is as follows:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        vector<vector<int>> dp(n,vector<int>(3,0));
        dp[0][0] = -prices[0];
        for (int i = 1;i<n;i++)
        {
            dp[i][0] = max(dp[i-1][0],dp[i-1][1]-prices[i]);
            dp[i][1] = max(dp[i-1][1],dp[i-1][2]);
            dp[i][2] = dp[i][0] + prices[i];
        }
        return max(dp[n-1][1],dp[n-1][2]);
    }
};

 Above we use dp[i][0] to indicate the status of stock, dp[i][1] to indicate the status of no stock, and dp[i][2] to indicate the freezing period.

2. The best time to buy and sell stocks includes handling fees

Ritko Link: Rikko

Given an array of integers  prices, which  prices[i]represent  i the stock prices on the first day; the integers  fee represent the handling fees for trading stocks.

You can complete transactions an unlimited number of times, but you need to pay a transaction fee for each transaction. If you have already bought a stock, you cannot continue to buy another stock until you sell it.

Returns the maximum value of profit.

Note: A transaction here refers to the entire process of buying, holding and selling stocks, and you only need to pay a handling fee for each transaction.

 This question is a variant of the first question we did. Let's first analyze the details of this question:

First of all, there is no freezing period this time, and you can trade casually, but you need to pay a handling fee for each transaction. It should be noted here that a transaction refers to having stocks and then selling them. It can be understood that only when selling, you need to pay handling fees. And this question is the same as the first question, you can only buy new stocks if you sell the original stocks.

1. Status representation

Based on the experience of the previous question, we directly use f[i] to represent the maximum profit with stocks in hand on day i, and use g[i] to represent the maximum profit without stocks in hands on day i.

2. State transition equation

 Because there are only two states in this question, we analyze directly:

When there were stocks on the previous day, that is, day i-1, we did nothing and still had stocks on the i-th day. The current day is a state of no stocks, then we bought stocks on the previous day and we will be in the state of stocks on the i-th day.

所以f[i] = max(f[i-1],g[i-1]-p[i])

First of all, if there was no stock on the previous day, then you will still be in the state of no stock on the i-th day after doing nothing. If there were stocks on the previous day, then we sold the stocks and became the state of no stocks.

So g[i] = max(g[i-1],f[i-1] + p[i] -fee) //Note that you need to pay a handling fee for selling stocks

3. Initialization

Only the first day will be out of bounds, so we directly initialize the maximum profit of the first day of the two tables:

If you want stocks on the first day, you have to buy them, and the profit of the purchases will change from 0 to negative, so f[0] = -p[0]

If there is no stock on the first day, you can just do nothing, so g[0] = 0

4. Fill in the form

From left to right, fill in both forms together

5. Return value

It is enough to return the maximum profit of the selling state on the last day. (Because no stock in hand on the last day must be more profitable than stock in hand)

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
       int n = prices.size();
       vector<int> f(n,0),g(n,0);
       f[0] = -prices[0];
       for (int i = 1;i<n;i++)
       {
           f[i] = max(f[i-1],g[i-1]-prices[i]);
           g[i] = max(f[i-1]+prices[i]-fee,g[i-1]);
       }
       return g[n-1];
    }
};

3. The best time to buy and sell stocks III

Ritko Link: Rikko

Given an array whose th  element is the price of a given stock on the first  day. ii 

Design an algorithm to calculate the maximum profit you can make. You can complete up to  two  transactions.

Note: You cannot participate in multiple transactions at the same time (you must sell the previous stock before buying again).

 This question is basically the same as our previous question, except that there is a limit of two transactions at most. Let's start the analysis directly.

1. Status representation

Based on the experience of the first two questions, we first use f[i] to represent the maximum profit with stocks in hand on the i-th day, and g[i] to represent the maximum profit without stocks in the i-th day, but we found that such a state means that there is no limit A maximum of two transactions can be completed, so we can directly add one more state. Use f[i][0] to represent the maximum profit of stocks with 0 transactions on the i-th day, and f[i][1] to represent the i-th The maximum profit with stock in hand for 1 transaction on the day, f[i][2] represents the maximum profit with stock in hand for 2 transactions on the i-th day, and the same for g.

So f[i][j] means that it has traded j times on the i-th day and is in a stock state.

g[i][j] means that there are j transactions on the i-th day, and there is no stock.

2. State transition equation

When there were stocks on the previous day, that is, day i-1, we did nothing and still had stocks on the i-th day. The current day is a state of no stocks, then we bought stocks on the previous day and we will be in the state of stocks on the i-th day.

So f[i][j] = max(f[i-1][j],g[i-1][j]-p[i]) Note: If there is stock in the previous day, then nothing On the i-th day, we still have stocks, so our number of transactions remains the same, or j times. If there was no stock status the day before, then buying stocks will result in a stock status, but we must note that only selling stocks is considered a transaction, so there are still j transactions that have not changed.

First of all, if there was no stock on the previous day, then you will still be in the state of no stock on the i-th day after doing nothing, and the number of transactions will not change. If there were stocks on the previous day, then we sell stocks and become no stocks, but selling stocks will add a transaction, and what we are asking for is actually the transaction of the i-th day, that is to say, after adding a transaction The number of transactions becomes j, so when seeking the profit of the previous day with stocks, it should be based on the number of transactions of j-1 (because there were stocks the previous day, selling on the i-th day will become the state of no stocks, once the number of transactions is sold +1, if the i-th day is the j transaction by default, then the i-1 day is the j-1 transaction)

所以g[i] = max(g[i-1][j],f[i-1][j-1]+p[i])

3. Initialization

Through the state transition equation, it can be found that each time the maximum value of the corresponding number of transactions in the previous day is required, and in order not to affect the maximum value of the data in the original table, each data in the table is initialized to the minimum value of the integer, but due to - The existence of p[i] will cause the minimum value of the integer to overflow, so we only take half of the minimum value of the integer.

If there is a stock on the first day and no transaction (that is, no sale), then the profit will change from 0 to negative, so f[0][0] = -p[0]

There is no stock on the first day and the number of transactions is 0, then you can do nothing, so g[0][0] = 0

4. Fill in the form

Each row is from top to bottom, each column is from left to right, and the two tables are filled together

5. Return value

It is enough to return that the last day is in the selling state and the transaction is the maximum profit among the three types of 0, 1, and 2. (Because the topic only limits no more than 2 transactions, but there is no guarantee that the more transactions, the greater the profit. When there is only one day's stock, no transaction is the most profitable)

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        const int Min = -0x3f3f3f3f;
        vector<vector<int>> f(n,vector<int>(3,Min));
        auto g = f;
        f[0][0] = -prices[0];
        g[0][0] = 0;
        for (int i = 1;i<n;i++)
        {
            for (int j = 0;j<3;j++)
            {
                f[i][j] = max(f[i-1][j],g[i-1][j]-prices[i]);
                g[i][j] = g[i-1][j];
                if (j>=1)
                {
                    g[i][j] = max(g[i-1][j],f[i-1][j-1]+prices[i]);
                }
            }
        }
        int ret = g[n-1][0];
        for (int i = 1;i<3;i++)
        {
            if (ret<g[n-1][i])
            {
                ret = g[n-1][i];
            }
        }
        return ret;
    }
};

It should be noted that our f[i-1][j-1] will not cross the boundary only when j>=1, so when j = 0, we only need to let g[i][ j] = g[i-1][j]

4. The best time to buy and sell stocks IV

Ritko Link: Rikko

Given an array of integers  prices whose first  element   is the price of a given stock on the first  day, and an integer   . iprices[i]i k

Design an algorithm to calculate the maximum profit you can make. You can complete at most  k transactions. In other words, you can buy at most  k and sell  k at most.

Note: You cannot participate in multiple transactions at the same time (you must sell the previous stock before buying again).

 In fact, it is not difficult for everyone to find that the difference between this question and our previous question is only the maximum limit of transactions, and we only need to modify the two transactions in the previous question to k transactions.

1. Status representation

f[i][j] means that it has traded j times on the i-th day and is in a stock state.

g[i][j] means that there are j transactions on the i-th day, and there is no stock.

2. State transition equation

When there were stocks on the previous day, that is, day i-1, we did nothing and still had stocks on the i-th day. The current day is a state of no stocks, then we bought stocks on the previous day and we will be in the state of stocks on the i-th day.

So f[i][j] = max(f[i-1][j],g[i-1][j]-p[i]) Note: If there is stock in the previous day, then nothing On the i-th day, we still have stocks, so our number of transactions remains the same, or j times. If there was no stock status the day before, then buying stocks will result in a stock status, but we must note that only selling stocks is considered a transaction, so there are still j transactions that have not changed.

First of all, if there was no stock on the previous day, then you will still be in the state of no stock on the i-th day after doing nothing, and the number of transactions will not change. If there were stocks on the previous day, then we sell stocks and become no stocks, but selling stocks will add a transaction, and what we are asking for is actually the transaction of the i-th day, that is to say, after adding a transaction The number of transactions becomes j, so when seeking the profit of the previous day with stocks, it should be based on the number of transactions of j-1 (because there were stocks the previous day, selling on the i-th day will become the state of no stocks, once the number of transactions is sold +1, if the i-th day is the j transaction by default, then the i-1 day is the j-1 transaction)

所以g[i] = max(g[i-1][j],f[i-1][j-1]+p[i])

3. Initialization

Through the state transition equation, it can be found that each time the maximum value of the corresponding number of transactions in the previous day is required, and in order not to affect the maximum value of the data in the original table, each data in the table is initialized to the minimum value of the integer, but due to - The existence of p[i] will cause the minimum value of the integer to overflow, so we only take half of the minimum value of the integer.

If there is a stock on the first day and no transaction (that is, no sale), then the profit will change from 0 to negative, so f[0][0] = -p[0]

There is no stock on the first day and the number of transactions is 0, then you can do nothing, so g[0][0] = 0

4. Fill in the form

Each row is from top to bottom, each column is from left to right, and the two tables are filled together

5. Return value

It is enough to return that the last day is in the selling state and the transaction is the largest profit among K types. (Because the topic only limits no more than K transactions, but there is no guarantee that the more transactions, the greater the profit. When there is only one day's stock, no transaction is the most profitable)

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        int n = prices.size();
        const int Min = -0x3f3f3f3f;
        vector<vector<int>> f(n,vector<int>(k+1,Min));
        auto g = f;
        f[0][0] = -prices[0];
        g[0][0] = 0;
        for (int i = 1;i<n;i++)
        {
            for (int j = 0;j<k+1;j++)
            {
                f[i][j] = max(f[i-1][j],g[i-1][j]-prices[i]);
                g[i][j] = g[i-1][j];
                if (j>=1)
                {
                    g[i][j] = max(g[i-1][j],f[i-1][j-1]+prices[i]);
                }
            }
        }
        int ret = g[n-1][0];
        for (int i = 1;i<k+1;i++)
        {
            if (ret<g[n-1][i])
            {
                ret = g[n-1][i];
            }
        }
        return ret;
    }
};

Note: When we had two transactions in the previous question, we had to open 3 positions. This is because there are still 0 transactions, that is, no transactions, so when this question gives K transactions, we need to add 1 more to represent the 0th transaction.

Guess you like

Origin blog.csdn.net/Sxy_wspsby/article/details/131353716