Best time to buy and sell stocks IV

Method 1: Dynamic programming
ideas and algorithms

Similar to other stock problems, we use a series of variables to store the "buy" status, and then use a series of variables to store the "sell" status. This problem can be solved through dynamic programming.

We use to represent the maximum profit in this case for exactly jj transactions for the price in the \textit{buy}[i][j]buy[i][j]array , and currently hold a stock in hand; use to represent exactly jj transactions, and currently hold no stock in hand. Stocks, the maximum profit in this case.\textit{prices}[0..i]prices[0..i]\textit{sell}[i][j]sell[i][j]

Then we can derive the state transition equation. For \textit{buy}[i][j]buy[i][j], we consider whether the stock currently held was bought on day ii. If it is bought on day ii, then on day i-1i−1, we do not hold the stock, and the corresponding state is \textit{sell}[i-1][j]sell[i−1][j ], and the purchase cost of \textit{prices}[i]prices[i] needs to be deducted; if it is not purchased on day ii, then on day i-1i−1, we hold the stock in hand, corresponding to the status \textit{buy}[i-1][j]buy[i−1][j]. Then we can get the state transition equation:

\textit{buy}[i][j] = \max \big\{ \textit{buy}[i-1][j], \textit{sell}[i-1][j] - \textit{price}[i] \big\}

buy[i][j]=max{buy[i−1][j],sell[i−1][j]−price[i]}

In the same way, \textit{sell}[i][j]sell[i][j],if it is sold on day ii, then on day i-1i−1, we hold the stock in hand, corresponding to the state \textit{buy}[i-1][j-1]buy[i− 1][j−1], and the selling profit of \textit{prices}[i]prices[i] needs to be increased; if it is not sold on the ii day, then on the i-1i−1 day, we have If you do not hold stocks, the corresponding state is \textit{sell}[i-1][j]sell[i−1][j]. Then we can get the state transition equation:

\textit{sell}[i][j] = \max \big\{ \textit{sell}[i-1][j], \textit{buy}[i-1][j-1] + \textit{price}[i] \big\}

sell[i][j]=max{sell[i−1][j],buy[i−1][j−1]+price[i]}

Since after all nn days are over, the maximum profit corresponding to not holding stocks in hand must be strictly due to the maximum profit corresponding to holding stocks in hand. However, the number of completed transactions is not always better (for example, the array is \textit{prices}pricesmonotonically decreasing , it is optimal if we do not make any transactions), so the final answer is \textit{sell}[n-1][0..k]sell[n−1][0..k]the maximum value in .

detail

In the above state transition equation, determining the boundary conditions is a very important step. We can consider setting all \textit{buy}[0][0..k]buy[0][0..k]and \textit{sell}[0][0..k]sell[0][0..k]as boundaries.

For \textit{buy}[0][0..k]buy[0][0..k], since there is only a \textit{prices}[0]prices[0]unique stock price, we cannot have any transactions, then we can set all \textit{buy}[0][1..k]buy[0][1..k]to one A very small value indicates an illegal state. And for \textit{buy}[0][0]buy[0][0], its value is - , that is, "we bought the stock at the price -\textit{prices}[0]−prices[0]on day 00 " is the only way to satisfy the need to hold the stock.\textit{prices}[0]prices[0]

For \textit{sell}[0][0..k]sell[0][0..k], similarly we can put all \textit{sell}[0][1..k]sell[0 ][1..k] is set to a very small value, indicating an illegal state. For \textit{sell}[0][0]sell[0][0], its value is 00, that is, "we do nothing on day 00" is the only way to satisfy the requirement that we do not hold stocks. .

After setting the boundaries, we can use a double loop, within the range of i\in [1,n), j \in [0, k]i∈[1,n),j∈[0,k] Perform state transfer. It should be noted that the state transition equation of \textit{sell}[i][j]sell[i][j] contains \textit{buy}[i-1][j-1]buy[i−1] [j−1], when j=0j=0, it represents an illegal state, so when j=0j=0, we do not need to \textit{sell}[i][j]sell[i][j] Just transfer it so it stays at 00.

The last thing to note is that the maximum value of kk in this question can reach 10^910 

code

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        if (prices.empty()) {
            return 0;
        }

        int n = prices.size();
        k = min(k, n / 2);
        vector<vector<int>> buy(n, vector<int>(k + 1));
        vector<vector<int>> sell(n, vector<int>(k + 1));

        buy[0][0] = -prices[0];
        sell[0][0] = 0;
        for (int i = 1; i <= k; ++i) {
            buy[0][i] = sell[0][i] = INT_MIN / 2;
        }

        for (int i = 1; i < n; ++i) {
            buy[i][0] = max(buy[i - 1][0], sell[i - 1][0] - prices[i]);
            for (int j = 1; j <= k; ++j) {
                buy[i][j] = max(buy[i - 1][j], sell[i - 1][j] - prices[i]);
                sell[i][j] = max(sell[i - 1][j], buy[i - 1][j - 1] + prices[i]);   
            }
        }

        return *max_element(sell[n - 1].begin(), sell[n - 1].end());
    }
};


Note that in the state transition equation, \textit{buy}[i][j]buy[i][j] and \textit{sell}[i][j]sell[i][j] both start from \textit{ buy}[i-1][..]buy[i−1][..] and \textit{sell}[i-1][..]sell[i−1][..] are transferred, Therefore we can use one-dimensional arrays instead of two-dimensional arrays for state transfer, that is:

\begin{cases} b[j] \leftarrow \max \big\{ b[j], s[j] - \textit{price}[i] \big\} \\ \\ s[j] \leftarrow \max \big\{ s[j], b[j-1] + \textit{price}[i] \big\} \end{cases}
  
b[j]←max{b[j],s[j]−price[i]}
s[j]←max{s[j],b[j−1]+price[i]}

 

Such state transition equations will become different due to state coverage. For example, if we calculate \textit{b}bss first and then ss, then when s[j]s[j] is calculated, the value of the b[j-1]b[j−1] item included in the state transition equation has been overwritten. , that is, it should have been \textit{buy}[i-1][j-1]buy[i−1][j−1]transferred from a two-dimensional representation, but now it has become\textit{buy}[i-1][j-1]buy[i−1][j−1]

But it's still correct. We consider the state transition equation of \textit{buy}[i][j-1]buy[i][j−1]:

b[j-1] \leftarrow \textit{buy}[i][j-1] = \max \big\{ \textit{buy}[i-1][j-1], \textit{sell}[i-1][j-1] - \textit{price}[i] \big\}
b[j−1]←buy[i][j−1]=max{buy[i−1][j−1],sell[i−1][j−1]−price[i]}

Then the state transition equation of s[j]s[j] is actually:

s[j] \leftarrow \max \big\{ s[j], \textit{buy}[i-1][j-1] + \textit{prices}[i], \textit{sell}[i-1][j-1] \big\}
s[j]←max{s[j],buy[i−1][j−1]+prices[i],sell[i−1][j−1]}

Why does the term \textit{sell}[i-1][j-1]sell[i−1][j−1] appear in the state transition equation of s[j]s[j]? In fact, we put "buy at \textit{prices}[i]prices[i] on day ii and sell at \textit{prices}[i]prices[i] on the same day ” is regarded as a transaction, so the corresponding income is:

\textit{sell}[i-1][j-1] - \textit{prices}[i] + \textit{prices}[i]
sell[i−1][j−1]−prices[i]+prices[i]

That is, \textit{sell}[i-1][j-1]sell[i−1][j−1] itself. In this case of a transaction within the same day, the income is zero. It does not bring additional income, so it has no impact on the final answer. The state transition equation is still essentially correct.

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        if (prices.empty()) {
            return 0;
        }

        int n = prices.size();
        k = min(k, n / 2);
        vector<int> buy(k + 1);
        vector<int> sell(k + 1);

        buy[0] = -prices[0];
        sell[0] = 0;
        for (int i = 1; i <= k; ++i) {
            buy[i] = sell[i] = INT_MIN / 2;
        }

        for (int i = 1; i < n; ++i) {
            buy[0] = max(buy[0], sell[0] - prices[i]);
            for (int j = 1; j <= k; ++j) {
                buy[j] = max(buy[j], sell[j] - prices[i]);
                sell[j] = max(sell[j], buy[j - 1] + prices[i]);   
            }
        }

        return *max_element(sell.begin(), sell.end());
    }
};


Complexity analysis

Time complexity: O(n\min(n, k))O(nmin(n,k)), where nn is the size of the array \textit{prices}prices, that is, the time it takes for us to use a double loop for dynamic programming .

Space complexity: O(n\min(n, k))O(nmin(n,k)) or O(\min(n, k))O(min(n,k)), depending on how we use two Dimensional array or one-dimensional array for dynamic programming.

                                                                                                                                                         

Guess you like

Origin blog.csdn.net/aliyonghang/article/details/128328280