[Graphic Algorithm] Classic and regular dynamic planning-the best time to buy and sell stocks

>_<

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

How do you trade to get the most profit?

 
 

A. Unlimited number of transactions

A total of two states [ not float ] [ holdings ]
dp [i] [0] is the meaning of the first day i do not stake the maximum funding
dp [i] [1] is the meaning of the i-th day of the largest holdings of funds
 
Here is not holding [0], holding [1] means the state of the day rather than the action-dp[i][0] means that it is not holding shares on the i-th day, not the i-th The act of selling stocks happens every day - understanding this sentence is the key to solving all stock problems
 
Insert picture description here

class Solution {
    
    
    public int maxProfit(int[] prices) {
    
    
        int len = prices.length;
        int[][] dp = new int[len][2];
        // 初始化
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        // 状态转移
        for(int i = 1; i < len; i++) {
    
    
            dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
            dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
        }
        return dp[len - 1][0];
    }
}

 
 

B. Restrict one-time sale

There are still a total of two states [not holding shares] [holding shares],
but note that since they can only be bought and sold once, the two states cannot be converted at will as in the previous question-they can only be converted from [holding shares] to [not holding shares]. But not reverse conversion
 
Insert picture description here

class Solution {
    
    
    public int maxProfit(int[] prices) {
    
    
        int len = prices.length;
        int[][] dp = new int[len][2];
        // 初始化
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        // 状态转移
        for(int i = 1; i < len; i++) {
    
    
            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[len - 1][0];
    }
}

 
 

C. Restrict two sales

A method: multi-state
 
due to the limitation of the number of trading, a total of five states:
dp [i] [0] state is doing nothing (fixed to 0)
dp [i] [1] The state is the first time held Unit
dp [i] [2] is a state of not holding the primary
dp [i] [3] of state 2nd holding
dp [i] [4] is a state of not holding 2nd
 
time The state transition of is not the two-way transition of the two states as in the first example, but a one-way process
 
Insert picture description here

class Solution {
    
    
    public int maxProfit(int[] prices) {
    
    
        int len = prices.length;
        int[][] dp = new int[len][5];
        // 初始化
        dp[0][1] = -prices[0];
        dp[0][3] = -prices[0];
        // 状态转移
        for(int i = 1; i < len; 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[len - 1][4];
    }
}

 

Method 2: Regular three-dimensional dynamic programming
 
dp[i][j][1] means: on the i-th day, the j-th transaction, the holding status
dp[i][j][0] means: On the i-th day, the j-th transaction, the state of not holding stocks
 
. Observe intuitively from the figure:
(1) Regardless of the number of transactions (j=whatever), the initial value of holdings (k=1) is negative, no The initial value of holdings (k=0) is 0-it will be used during initialization
(2) When jumping from no holding to holding state, the number of transactions must also jump by 1; when jumping from holding state When it reaches the state of not holding shares, it must not jump out of this transaction-it will be used when writing dp transfer
 
Insert picture description here

class Solution {
    
    
    public int maxProfit(int[] prices) {
    
    
        int len = prices.length;
        int[][][] dp = new int[len][3][2];
        // 初始化
        dp[0][1][1] = -prices[0];
        dp[0][2][1] = -prices[0];
        // 状态转移
        for(int i = 1; i < len; i++) {
    
    
            for(int j = 1; j < 3; j++) {
    
    
                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[len - 1][2][0];
    }
}

 
 

D. Restrict k times of buying and selling

At this time, it is impossible to try to use the [multi-state] idea to express all states, because the number of transactions cannot be written dead-this question can only use three-dimensional dp.
 
In fact, this is the second way of writing the previous question. Remember to read the picture of the previous question to understand .

class Solution {
    
    
    public int maxProfit(int k, int[] prices) {
    
    
        int len = prices.length;
        int[][][] dp = new int[len][k + 1][2];
        // 初始化
        for(int j = 1; j < k + 1; j++) {
    
    
            dp[0][j][0] = 0;
            dp[0][j][1] = -prices[0];
        }
        // 状态转移
        for(int i = 1; i < len; i++) {
    
    
            for(int j = 1; j < k + 1; j++) {
    
    
                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[len - 1][k][0];
    }
}

 
 

E. Handling fee

The simplest variant of the motif, you can charge a fee when you sell the stock

class Solution {
    
    
    public int maxProfit(int[] prices, int fee) {
    
    
        int len = prices.length;
        int[][] dp = new int[len][2];
        // 初始化
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        // 状态转移
        for(int i = 1; i < len; i++) {
    
    
            dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee);
            dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
        }
        return dp[len - 1][0];
    }
}

 
 

F. Freezing period

If you really understand the multi-state [solution], then this question is very simple - a total of three state
 
dp [i] [0] represents not holding (non-freezing period)
dp [i] [1] represents a shareholding
dp [ I] [2] represented by not holding (freezing period)
 
key point is that (1) the conversion to clarify the relationship between these three states (2) of the last in a frozen / not frozen period are likely
 
Insert picture description here

class Solution {
    
    
    public int maxProfit(int[] prices) {
    
    
        int len = prices.length;
        int[][] dp = new int[len][3];
        // 初始化
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        dp[0][2] = 0;
        // 状态转移
        for(int i = 1; i < len; i++) {
    
    
            dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][2]);
            dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
            dp[i][2] = dp[i - 1][1] + prices[i];
        }
        return Math.max(dp[len - 1][0], dp[len - 1][2]);
    }
}

 
 
 
 

Understanding and supplement

  1. Think about it, why is "no limit on the number of transactions" a cross-conversion of 2 states, and "restricted 2 transactions" is a one-way conversion of 5 states? In fact, the cross-transformation of " unlimited buying and selling" can be regarded as a one-way transformation of infinite states (do nothing, the first time is 1, the first time is 0, the second time is 1, the second time is 0, the third time 1, the third time 0...)
  2. For the simplest motif "no limit on the number of transactions", there is a more efficient way of thinking- greedy . That is , the superposition of profits. As long as the stock price rises relative to the previous day, this profit is accumulated, and the final result is the global optimal total profit ( int diff = prices[i] - prices[i - 1]; if(diff > 0) { res += diff; })
  3. In the code of "Limit 2 transactions", the return value is the value in the bottom right corner of the dp table, meaning [the last day, the second transaction, the state of non-holding], but because it may only be traded once, the final The result may also be [last day, first transaction, non-holding status]? In fact, at the time of initialization, the initial value of [the first day, the first transaction, the holding status] [the first day, the second transaction, the holding status] are all -prices[0], and the first and second The code for the downward conversion of each transaction is the same-that is, when the number of transactions is less than 2 times, the "second transaction" itself is meaningless, it is a complete copy of the "first transaction" -so we can rest assured Use the lower right corner of dp as the return value
  4. In multiple variants, the use of multi-state approach, we found that all states are often difficult to find, you can find out the status of the conversion relationship is not simple, this what skills it? For a certain state, think about which state it can be transformed from
  5. The above dp can be optimized for rolling arrays -directly delete a dimension from the original code, it is very simple, no code will be given

 
 
 
 

 
 
 
 

 
 
 
 

 
 
 
 

E N D END END

B Y A L O L I C O N BY A LOLICON BYALOLICON

Guess you like

Origin blog.csdn.net/m0_46202073/article/details/112395067