Dynamic programming: everything is changing, and it will take you to understand the series of stock problems

Foreword:

For the problem of buying and selling stocks, the most critical thing is how we deal with the problem (for each day, should we describe the buying and selling of the day or just describe the status of only or not holding the stock every day?) We should Describe the status of holding stocks every day, because the status of holding stocks every day is easy to describe, there are only two states of holding and not holding, but if you choose to describe which day you buy and sell similar to this state, describe it it's complicated

1. The best time to buy and sell stocks I (can only buy once)

Title Description (Link: Leetcode )

problem solving ideas

We analyze it using five parts of motion rules:

1. Array subscript and meaning: Here we use a two-dimensional array as the dp array, why use a two-dimensional array? Because which day is a variable, each day also has two states: holding and not holding stocks, so we use dp[n][2] as the dp array, n represents which day, and 2 represents two different state, dp[][] represents the maximum profit in a certain state of the day.

2. Recursive formula: For the current problem, it can only be bought and sold once. For the state of each day, dp[n][0] represents holding stocks: if you hold stocks, there are two possibilities: in Hold it the day before, or buy it on the same day, we take the maximum profit, so: dp[n][0]=max(dp[n-1][0],-prices[i]])( Since you can only buy and sell once, if you buy on the same day, it means that you must have not bought before, so the profit you get from buying today is -prices[i]), and dp[n][1] represents the price that does not hold stocks on that day State, there are also two possibilities of composition: one is inherited from dp[n-1][0], that is, the state of the previous day is not held, today’s state is the continuation of the state of the previous day, and the second One is dp[n-1][0]+prices[i], that is, the stock was held yesterday, but the stock was sold today, and the maximum value of the two is also taken.

3. Initialization: The conclusion we can draw from the recursive formula is: our state of the next day depends on the state of the previous day, so the correctness of the dp array on the first day is very important, dp[0][0]: represents the first day Holding stocks for one day, so its profit is: --prices[0] dp[0][1] The first day does not hold stocks, so its profit is: 0

4. Traversal order: Since the front is pushed out from the back, the traversal order is naturally from front to back

5. Print the dp array: check the correctness of the final result by printing the dp array

Code

class Solution {
    public int maxProfit(int[] prices) {
        //排除特殊情况
        if(prices.length==1){
            return 0;
        }
        //创建dp数组
        int[][]dp=new int[prices.length][2];
        dp[0][0]=-prices[0];
        dp[0][1]=0;
        for(int i=1;i<prices.length;++i){
            dp[i][0]=Math.max(dp[i-1][0],-prices[i]);
            dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);
        }
        return dp[prices.length-1][1];
    }
}

2. The best time to buy and sell stocks II (you can buy countless times)

Title Description (Link: Leetcode )

problem solving ideas

We still use the dynamic five-part analysis:

1. Array subscripts and their meanings: each day also has two states: holding and not holding stocks, so we use dp[n][2] as the dp array, n represents which day, 2 represents Two different states, dp[][] represents the maximum profit in a certain state of the day.

2. Recursive formula: dp[n][0] means holding stocks on that day, there are two possibilities: ① Continue the previous state of having stocks ② There was no stocks the day before, but we bought new stocks today, we still Take the maximum of the two: dp[n][0]=max(dp[n-1][0],dp[n-1][1]-prices[i]),dp[n][1] It means not holding stocks on the same day, there are also two possibilities: holding the previous day but selling them today, or continuing the state of no stocks the previous day, the state equation is: dp[n][1]=max(dp[n -1][1],dp[n-1][1]+prices[i])

3. Initialization: Holding stocks on the first day: dp[0][0]=-prices[0] Not holding stocks on the first day: dp[0][1]=0

4. Traversal order: consistent with the best time to buy and sell stocks 1, traverse from front to back

5. Print: Confirm the correctness of the result by printing the array

Code

class Solution {
    public int maxProfit(int[] prices) {
        //创建dp数组
        int[][]dp=new int[prices.length][2];
        //初始化
        dp[0][0]=-prices[0];
        //进行遍历
        for(int i=1;i<prices.length;++i){
            dp[i][0]=Math.max(dp[i-1][1]-prices[i],dp[i-1][0]);
            dp[i][1]=Math.max(dp[i-1][0]+prices[i],dp[i-1][1]);
        }
        return dp[prices.length-1][1];
    }
}

3. The best time to buy and sell stocks III (you can only buy twice)

Title Description (Link: Leetcode )

problem solving ideas

Different from the previous two application scenarios of buying and selling stocks II, this topic adds restrictions on buying and selling stocks, limiting the number of times to buy and sell stocks (only two transactions are allowed), which seems to be similar to buying and selling stocks 1 (only one transaction is allowed for buying and selling stocks 1) ), but the scene has changed a lot: the difference between buying and selling stocks I and II is only the profit when buying stocks in the recursive formula (I is dp[n][0]=max(dp[n-1][ 0],-prices[i]]), II is: dp[n][0]=max(dp[n-1][0],dp[n-1][1]-prices[i])) , but once the stock can only be bought and sold twice, the scene becomes more complicated. At this time, it is necessary to redefine 1. The array subscript and its meaning dp The array subscript and its own meaning: dp[n][0]: the first No operations have been performed for n days: dp[n][1]: holding stocks for the first time dp[n][2]: not holding stocks for the first time dp[n][3]: holding stocks for the second time dp[n][4] holds no stock for the second time.

2. Recursion formula: The recursion formula in each state is also different, let’s explain them one by one: dp[n][1]=max(dp[n-1][1], dp[n-1] ][0]-prices[i]) (the state of holding stocks for the first time the previous day or the stock was not purchased the previous day, but just purchased today), dp[n][2]=max(dp[n-1][ 2], dp[n-1][1]+prices[i]) (continuing the state of not holding the previous day for the first time or holding the previous day, selling today) dp[n][3]=max(dp [n-1][3],dp[n-1][2]-prices[i]) (continuation of the second holding of the previous day or no holding of the previous day, just purchased today) dp[n][ 4]=max(dp[n-1][4],dp[n-1][3]+prices[i])

3. Initialization

dp[0][0]: No operation on the first day, so the result is 0, dp[0][1] The first purchase on the first day, the profit is -prices[0], dp[0][2 ] Selling stocks on the first day, the profit is 0 dp[0][3] Buying stocks for the second time on the first day, the profit is (-prices[0], buying and selling on the first day and then buying) dp[0 ][4] Selling for the second time, the profit is also 0

4. Traversal order: consistent with the previous ones, they are all traversed from front to back

5. Print to check the correctness of the results

Code

class Solution {
    public int maxProfit(int[] prices) {
        //定义数组
        int[][]dp=new int[prices.length][5];

        //初始化
        dp[0][0]=0;
        dp[0][1]=-prices[0];
        dp[0][2]=0;
        dp[0][3]=-prices[0];
        dp[0][4]=0;
        //进行遍历
        for(int i=1;i<prices.length;++i){
            dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]-prices[i]);
            dp[i][2]=Math.max(dp[i-1][2],dp[i-1][1]+prices[i]);
            dp[i][3]=Math.max(dp[i-1][3],dp[i-1][2]-prices[i]);
            dp[i][4]=Math.max(dp[i-1][4],dp[i-1][3]+prices[i]);
        }
        return dp[prices.length-1][4];
    }
}

4. The best time to buy and sell stocks IV (can only buy k times)

Title Description (Link: Leetcode )

problem solving ideas

The problem-solving idea is similar to that of buying and selling stocks III: buying and selling stocks III plus the state of doing nothing defines 5 states (not operated, first buy, first sell, second buy, second Selling for one time), so there is only one thing that needs to be changed when buying and selling stocks IV compared to III, that is, the status of each day increases: so we adopt a circular method, as follows: where k represents the maximum number of times allowed to buy and sell

for(int j=0;j<2*k-1;j+=2){
                dp[i][j+1]=Math.max(dp[i-1][j+1],dp[i-1][j]-prices[i]);
                dp[i][j+2]=Math.max(dp[i-1][j+2],dp[i-1][j+1]+prices[i]);
            }

We directly give the complete code (similar to buying and selling stocks III)

class Solution {
    public int maxProfit(int k, int[] prices) {
        //创建数组
        int[][]dp=new int[prices.length][2*k+1];
        //初始化
        for(int i=0;i<2*k;i+=2){
            dp[0][i+1]=-prices[0];
        }
        //遍历
        for(int i=1;i<prices.length;++i){
            for(int j=0;j<2*k-1;j+=2){
                dp[i][j+1]=Math.max(dp[i-1][j+1],dp[i-1][j]-prices[i]);
                dp[i][j+2]=Math.max(dp[i-1][j+2],dp[i-1][j+1]+prices[i]);
            }
        }
        return dp[prices.length-1][2*k];
    }
}

5. The best time to buy and sell stocks V (including the freezing period)

Title Description (Link: Leetcode )

problem solving ideas

What is different from the description of the previous topic is that there is a freezing period for the stock problem this time, and it is precisely because of this freezing period that the subscripts corresponding to our dp array and the meaning of the dp array will undergo certain changes: we used to Just divide the state of each day into two types: holding stocks and not holding stocks (not holding stocks includes the state of selling stocks just today and continuing to sell stocks before), but once the concept of freezing period is introduced, we It is necessary to subdivide the status of selling stocks: 1. Just sold the stock today 2. It is in the freeze period (sold stock yesterday) 3. The stock was sold before and not in the freeze period, so the total status is 4 On this basis, plus the status of holding stocks, use the five-step dynamic rule to analyze this:

①The meaning of the dp array subscript and its array meaning dp[i][0]: represents the currently held stock dp[i][1]: represents the current stock to be sold (the latest is to sell the stock the day before yesterday); dp[i] [2] means that the stock has just been sold today; dp[i][3] means that it is currently in the freezing period

②Recursive formula: dp[i][0]=max(d[i-1][0]max(dp[i-1][3]-prices[i],dp[i-1][1] -prices[i]));(There are stocks in the hands today, it may be a continuation of the state of stocks in the hands of the previous day and yesterday was in the freezing period, buy stocks today, or maintain the state of selling stocks yesterday, and buy stocks today); dp[i][1]=max(dp[i-1][3],dp[i-1][1]) (Keep the previous state of selling stocks or it was in the freezing period yesterday, enter today to keep selling stocks ) dp[i][2]=d[i][0]+prices[i] (I just sold the stock today, which means that there must be stock in my hand the day before, so dp[i][2] is only the same as the previous day related to dp[i-1][0]); dp[i][3]=dp[i-1][2] (today’s freezing period means that the stock must have just been sold yesterday, so only by yesterday dp[i-1][2] decision)

③Initialization: dp[0][0]=-prices[0] (just bought stocks today) dp[0][1]=0 (it is actually illegal to have this state on day 0, we can set it It is understood that there is no stock in hand today, so it is initialized to 0) dp[0][2]=0 (the stock was bought and sold directly after buying today, so the profit is 0) dp[0][3]=0 (it is frozen today The state of the period is also illegal, we initialize it to 0)

④Traversal order: still from the front to the back, so the traversal order is also from front to back

⑤ Print array: Judging legality by printing dp array

Code

class Solution {
    public int maxProfit(int[] prices) {
        //创建数组
        int[][]dp=new int[prices.length][4];
        //进行初始化
        dp[0][0]=-prices[0];//0代表持有股票
        dp[0][1]=0;//1代表保持卖出股票
        dp[0][2]=0;//2表示卖出股票
        dp[0][3]=0;//3表示在冷冻期内
        //进行遍历循环
        for(int i=1;i<prices.length;++i){
         dp[i][0]=Math.max(dp[i-1][0],Math.max(dp[i-1][3]-prices[i],dp[i-1][1]-prices[i]));
         dp[i][1]=Math.max(dp[i-1][1],dp[i-1][3]);
         dp[i][2]=dp[i-1][0]+prices[i];
         dp[i][3]=dp[i-1][2];
        }
        //返回最后卖出股票中的最大值
        return Math.max(dp[prices.length-1][1],Math.max(dp[prices.length-1][2],dp[prices.length-1][3]));
    }
}

6. The best time to buy and sell stocks VI (including handling fees)

Title Description (Link: Leetcode )

problem solving ideas

This question is basically the same as buying and selling stocks II. The only difference is that we need to add a handling fee when selling stocks, so it is reflected in the code that the recursive formula has changed:

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

Others are exactly the same as buying and selling stocks II: we give the code directly. 

Code

class Solution {
    public int maxProfit(int[] prices, int fee) {
        //定义dp数组
        int[][]dp=new int[prices.length][2];
        //初始化
        dp[0][0]=-prices[0];
        dp[0][1]=0;
        //进行遍历
        for(int i=1;i<prices.length;++i){
            dp[i][0]=Math.max(dp[i-1][1]-prices[i],dp[i-1][0]);
            dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]+prices[i]-fee);
        }
        return dp[prices.length-1][1];
    }
}

Guess you like

Origin blog.csdn.net/m0_65431718/article/details/130519895