The stock problem of dynamic programming--a common method to eliminate 6 problems

table of Contents

One: Introduction to the general framework of stocks

I. Introduction

Two: Exhaustive framework

Three: State transition framework

Four. Matters needing attention

V. Summary

Two: actual combat topic

Topic 1: The best time to buy and sell stocks (k =1)

Topic 2: The best time to buy and sell stocks 2 (k = positive infinity)

Topic 3: The best time to buy and sell stocks 3 (k = 2)

Topic 4: The best time to buy and sell stocks 3 (k = any integer)

Question 5: The best time to buy and sell stocks includes a freezing period

Topic 6: The best time to buy and sell stocks includes handling fees


One: Introduction to the general framework of stocks

I. Introduction

There are common issues in stock buying and selling. Let's first solve the analysis of the fourth question (limiting the maximum number of transactions to k) one by one.

Because the fourth question (limit the maximum number of transactions to k) is the most generalized form, the other questions are simplifications of this form.

The first question: Only conduct one transaction, which is equivalent to k = 1;

Question 2: Unlimited number of transactions, equivalent to k = positive infinity

The third question: Only conduct 2 transactions, which is equivalent to k = 2;

Questions 5 and 6: Unlimited number of times, additional conditions for six transaction freeze periods and handling fees are added.

Two: Exhaustive framework

For the stock issue, we do not use recursive thinking to exhaustively, but use state to exhaustively.

We go to every day, look at a total of several possible states, and then find out the choices corresponding to each state.

We enumerate all the states, and the purpose of the exhaustion is to update the state according to the corresponding selection.

Framework code flow chart:

for 状态1 in 状态1的所有取值:
    for 状态2  in  状态2的所有取值:
       for ...
          dp[状态1][状态2][...] = 择优(选择1,选择2,...)

For stock issues, there are three choices every day: buy, sell, and no operation. We use buy, sell, and rest to represent these three choices.

But the problem is that it is not every day that you can choose these three options arbitrarily, because sell must be after buy, and buy must be after sell.

Then the rest operation should be divided into two states, one is rest after buy (holding stocks), and the other is rest after sell (not holding stocks at this time).

Note that we also have a limit on the number of transactions k. That is to say, you can only operate under the premise of k> 0.

    All of the above are for exhaustive enumeration. There are three variables for the stock problem: the first is the number of days, the second is the maximum number of transactions allowed,

The third is the current holding state (usually 1 means holding, 0 means not holding). We use a three-dimensional number to assemble all combinations of these states.

dp[i][k][0 or 1]
0 <= i <= n-1, 1 <= k <= K
n为天数,K为最多交易数
此问题共n * K * 2种状态,全部穷举就能够搞定
for 0 <= i <= n:
    for 1 <= k <= K:
        for s in {0,1}:
            dp[i][k][s] = max{buy , sell , rest}

The last answer we want is dp[n-1][K][0], that is, on the last day, at most k transactions are allowed and how much profit can be obtained at most.

Three: State transition framework

The above has completed the exhaustive list of states. We think about the options for each state and how to update the state. We only look at the holding state.

Draw the state transition diagram.

Through the state transition diagram, we can clearly see how each state (0 and 1) is transferred,

According to this figure, let's write the state transition equation 1

dp[i][k][0] = max(dp[i-1][k][0] , dp[i-1][k][1] + price[i])

That is max (select rest, select sell)

Explanation of state transition equation: Today I do not hold stocks for two reasons:

1) I didn't hold it yesterday, I chose rest today, so I still didn't hold it today;

2) I held stocks yesterday, but sold, so I did not hold stocks today.

State transition equation 2:

dp[i][k][1] = max(dp[i-1][k][1] , dp[i-1][k-1][0] - price[i])

That is max (select rest, select buy)

Explanation of state transition equation:

Today I hold stocks, there are two possibilities:

1) Either I held the stock yesterday, and then choose rest today;

2) Either I didn't hold any stocks yesterday, but I chose to buy today.

Four. Matters needing attention

Changes in profit and changes in k

If you buy, you must subtract price[i] from the profit. If you sell, you must add prices[i] to the profit.

The biggest profit today is the larger of the two possible choices. And pay attention to the limit of k,

When we choose buy, we reduce k by 1, so we don't need to change k again when we sell.

base case

dp[-1][k][0] = 0

Explanation: Because i starts from 0, i = -1 means it has not started yet, and the profit at this time is 0.

dp[-1][k][1] = negative infinity

Explanation: At this time, it has not yet started, which means that it is impossible to hold stocks.

dp[i][0][0] = 0;

Explanation: Because k starts from 1, so k = 0 means that trading is not allowed at all. At this time, the profit is of course 0.

V. Summary

base case
dp[-1][k][0] = dp[i][0][0] = 0
dp[-1][k][1] = dp[i][0][1] = -无穷
状态转移方程
dp[i][k][0] = max(dp[i-1][k][0],dp[i-1][k][1] +prices[i])
dp[i][k][1] = max(dp[i-1][k][1],dp[i-1][k-1][0] - prices[i])

Programming supplement: How to program the array index to -1 to ensure that it does not overflow.

Two: actual combat topic

Topic 1: The best time to buy and sell stocks (k =1)

(Subject link: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/ )

Given an array prices, its i-th element prices[i] represents the price of a given stock on the i-th day.

You can only choose to buy this stock on a certain day, and choose to sell the stock on a different day in the future. Design an algorithm to calculate the maximum profit you can get.

Return the maximum profit you can get from this transaction. If you cannot make any profit, return 0.

Example 1:

Input: [7,1,5,3,6,4]
Output: 5
Explanation: Buy on the 2nd day (stock price = 1), and sell on the 5th day (stock price = 6). Maximum profit = 6-1 = 5.
     Note that the profit cannot be 7-1 = 6, because the selling price needs to be greater than the buying price; at the same time, you cannot sell the stock before buying

Idea: Apply the template directly, pay attention to dp[i][1] = Math.max( dp[i-1][1], -prices[i])

Among them is -prices[i], because k = 1, there is only one buying opportunity

class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        int[][] dp = new int[n][2];
        for(int i =0;i<n;i++){
            if(i-1 == -1){
                dp[i][0] = 0;
                dp[i][1] = -prices[i];
                continue;
            }
            dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i]);
            dp[i][1] = Math.max(dp[i-1][1],-prices[i]);
        }
        return dp[n-1][0];
    }
}

Optimized code:

Do not use a two-dimensional array, we only use variables

class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        int dp_i_0 =0;
        int dp_i_1 = Integer.MIN_VALUE;
        for(int i =0;i<n;i++){
            dp_i_0 = Math.max(dp_i_0,dp_i_1+prices[i]);
            dp_i_1 = Math.max(dp_i_1,-prices[i]);
        }
        return dp_i_0;
    }
}

Topic 2: The best time to buy and sell stocks 2 (k = positive infinity)

(Subject link: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ )

Given an array, its i-th element is the price of a given stock on the i-th day.

Design an algorithm to calculate the maximum profit you can get. You can complete as many transactions as possible (buying and selling a stock multiple times).

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

Example 1:

Input: [7,1,5,3,6,4]
Output: 7
Explanation: Buy on the 2nd day (stock price = 1), and sell on the 3rd day (stock price = 5), This exchange can make a profit = 5-1 = 4.
     Then, buy on the 4th day (stock price = 3), and sell on the 5th day (stock price = 6). This exchange can make a profit = 6-3 = 3.

Greedy algorithm: As long as the next day is larger than the current day, we will buy on the current day and sell on the next day

class Solution {
    public int maxProfit(int[] prices) {
        int res = 0;
        for(int i =0;i <prices.length-1;i++){
            if(prices[i] < prices[i+1]){
                res = res+prices[i+1]-prices[i];
            }
        }
        return res;
    }
}

Dynamic programming

class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
         int dp_i_0 = 0;
         int dp_i_1 = Integer.MIN_VALUE;
         for(int i =0;i<n;i++){
             dp_i_0 = Math.max(dp_i_0,dp_i_1+prices[i]);
             dp_i_1 = Math.max(dp_i_1,dp_i_0-prices[i]);
         }
         return dp_i_0;
    }
}

Topic 3: The best time to buy and sell stocks 3 (k = 2)

(Subject link: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/ )

Given an array, its i-th element is the price of a given stock on the i-th day.

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

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

Example 1:

Input: prices = [3,3,5,0,0,3,1,4]
Output: 6
Explanation:

Buy on the 4th day (stock price = 0) and sell on the 6th day (stock price = 3). This exchange can make a profit = 3-0 = 3.
Then, buy on the 7th day (stock price = 1) and sell on the 8th day (stock price = 4). This exchange can make a profit = 4-1 = 3.

Idea: k = 2 is different from the first question k = 1, and the second question k = positive infinity. Because k = 1 is close to the base case, positive infinity is equivalent to not considering k.

In this question, k = 2, which is equivalent to k being any positive integer.

We have the most primitive dynamic transfer equation

dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1]+prices[i] )

dp[i][k][1] = max(dp[i-1][k][1] , dp[i-1][k-1][0]-prices[i])

The above state transition equation is written according to the exhaustive framework we summarized, which means that we must

Exhaust all states. But for the first two questions, k is simplified in our exhaustive state, and for this question, we have to consider k.

Therefore, k must be exhaustively listed.

Idea: Use the most original framework and add another layer of loop of variable k

class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        int max_k = 2;
        int[][][] dp = new int[n][max_k+1][2];
        for(int i =0;i<n;i++){
            for(int k=max_k;k>=1;k--){
                if(i==0){
                    dp[i][k][0] =0;
                    dp[i][k][1] = -prices[i];
                    continue;
                }
                dp[i][k][0] = Math.max(dp[i-1][k][0],dp[i-1][k][1]+prices[i]);
                dp[i][k][1] = Math.max(dp[i-1][k][1],dp[i-1][k-1][0]-prices[i]);
            }
        }
        return dp[n-1][max_k][0];
    }
}

Note: 1) Don’t forget to process the -1 of the array

          2) Don't forget the continue statement

Topic 4: The best time to buy and sell stocks 3 (k = any integer)

(Subject link: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/ )

Given an integer array prices, its i-th element prices[i] is the price of a given stock on the i-th day.

Design an algorithm to calculate the maximum profit you can get. You can complete k transactions at most.

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

Example 1:

Input: k = 2, prices = [2,4,1]
Output: 2
Explanation: Buy on the 1st day (stock price = 2), and sell on the 2nd day (stock price = 4). This exchange can make a profit = 4-2 = 2.

Idea: Apply the most original template, pay attention to the for loop

class Solution {
    public int maxProfit(int k, int[] prices) {
        int n= prices.length;
        int[][][] dp = new int[n][k+1][2];
        if(n==0)return 0;
        for(int i =0;i<n;i++){
            for(int j =k;j>0;j--){
                if(i==0){
                    dp[i][j][0] =0;
                    dp[i][j][1] = -prices[i];
                    continue;
                }
                dp[i][j][0] =  Math.max(dp[i-1][j][0],dp[i-1][j][1]+prices[i]);
                dp[i][j][1] =  Math.max(dp[i-1][j][1],dp[i-1][j-1][0]-prices[i]);
            }
        }
        return dp[n-1][k][0];
    }
}

Question 5: The best time to buy and sell stocks includes a freezing period

(Subject link: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/ )

Given an integer array, the i-th element represents the stock price on the i-th day.

Design an algorithm to calculate the maximum profit. Under the following constraints, you can complete as many transactions as possible (buying and selling a stock multiple times):

You cannot participate in multiple transactions at the same time (you must sell the previous stock before buying again).
After selling the stock, you cannot buy the stock the next day (ie, the freezing period is 1 day).
Example:

Input: [1,2,3,0,2]
Output: 3 
Explanation: The corresponding transaction status is: [Buy, Sell, Freeze Period, Buy, Sell]

Idea: Add an additional constraint, which is equivalent to waiting a day after each sell before you can continue trading.

When programming, you can use the form of that two-dimensional array, or you can directly use variables to store

class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        int dp_i_0 =0;
        int dp_i_1 = Integer.MIN_VALUE;
        int dp_pre =0;
        for(int i =0;i<n;i++){
            int temp = dp_i_0;
            dp_i_0 = Math.max(dp_i_0,dp_i_1+prices[i]);
            dp_i_1 = Math.max(dp_i_1, dp_pre-prices[i]);
            dp_pre = temp;
        }
        return dp_i_0;
    }
}

Note: Use a temporary dp_pre to store the state of the previous day (not held at this time).

Topic 6: The best time to buy and sell stocks includes handling fees

(Subject link: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/ )

Given an integer array prices, where the i-th element represents the stock price on the i-th day; the non-negative integer fee represents the transaction fee for stocks.

You can complete transactions an unlimited number of times, but you need to pay a handling fee for each transaction. If you have already purchased a stock, you can no longer buy stocks before you sell it.

Returns the maximum profit obtained.

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

Example 1:

Input: prices = [1, 3, 2, 8, 4, 9], fee = 2
Output: 8
Explanation: Maximum profit that can be achieved:  
buy here prices[0] = 1
sell here prices[ 3] = 8
Buy here prices[4] = 4
Sell ​​here prices[5] = 9
Total profit: ((8-1)-2) + ((9-4)-2) = 8 .

Idea: Use code framework, just subtract one fee when buying

class Solution {
    public int maxProfit(int[] prices, int fee) {
        int n = prices.length;
        int dp_i_0 = 0;
        int dp_i_1 = Integer.MIN_VALUE;
        for(int i =0;i<n;i++){
            dp_i_0 = Math.max(dp_i_0,dp_i_1+prices[i]);
            dp_i_1 = Math.max(dp_i_1,dp_i_0-prices[i]-fee);
        }
        return dp_i_0;
    }
}

references

https://www.cnblogs.com/hanyuhuang/p/11083384.html

 

 

 

 

 

 

 

 

 

 

Guess you like

Origin blog.csdn.net/yezonghui/article/details/113791178