The best time to buy and sell stocks
The title
In version 1, the correct number of transactions is written in a template
Public static int maxProfit(int prices) {public static int maxProfit(int prices) {public static int maxProfit(int prices) {public static int maxProfit(int prices) { Int k = 1; int k = 1; int k = 1; int [][][] dp = new int[prices.length + 1][K + 1][2]; Dp [0][k][0] = 0; dp[0][k][0] = 0; Dp [0][k][1] = integer.min_value for (int k = 0; k <= K; k ++) { dp[0][k][1] = Integer.MIN_VALUE; } // In any day, if the number of trades is 0, it means that there is no trading, at this time, the maximum profit without holding the stock is 0, that is, dp[I][0][0] = 0; Dp [I][0][1] = intege.min_value; dp[I][0][1] = intege.min_value; for (int i = 0; i <= prices.length; i ++) { dp[i][0][1] = Integer.MIN_VALUE; } for (int I = 1; i <= prices.length; i ++) { for (int k = 1; k <= K; K + +) {/ / the first day, I the current trading times for k times, does not hold shares. Dp [I] [k] [0] = math.h Max (dp [k] [I - 1] [1] + prices] [I - 1, dp [I - 1] [k] [0]). Dp [I][k][1] = math. Max (dp[i-1][k-1][0] -prices [i-1], dp[i - 1][k][1]); }} return dp[prices.length][K][0];}} return dp[prices.length][K][0]; }Copy the code
The right reason
(1) Notice the base case, when should I assign negative infinity
(2) Pay attention to the fact that a transaction occurs when you buy a stock, otherwise the result is wrong
How to limit the number of transactions k?
Let’s say K is at most 2.
(1) First of all, the first transaction can take place on any day, as can the second transaction, but the second transaction must take place after the first transaction.
(2) Keep enumerating the time when the first transaction occurs, and then get a profit, but the actual saving is the maximum profit before the current number of days, after the first transaction. Therefore, after the maximum value is generated, the enumeration of the next day will get the same value
(3) Then the second transaction depends on the result of the first transaction. The second transaction depends on the result of the first transaction at different times, which may be different or the same. Then the maximum value after the last second transaction is passed to the last.
(4) In fact, it is equivalent to enumerating the situation of the maximum value of only one transaction, and then go through again, enumerating the situation of the second transaction. By limiting the size of the array, there must be only two transactions, but at different times, and never a third.
Take an example
The maximum values after enumerating the first transaction are [1, 2, 2, 2, 4, 5, 5]
Then enumerate the second transaction [-INF, 3, 3, 4, 5, 7, 7]
So remember, the enumeration is really the timing of the transaction, and the number of transactions is related to the number of iterations, so it’s finite
Version 2 is correct purely for the purpose of solving the problem, not the template
public int maxProfit(int[] prices) { if (prices.length == 0) { return 0; Int minBeforeI = prices[0];} // If the number of transactions is limited to one, consider not dynamic programming, but looking for the maximum difference in the array. int ans = 0; for (int i = 1; i < prices.length; I ++) {if (prices[I] >= minBeforeI) {ans = Math. Max (prices[I] -minbeforei); } else { minBeforeI = prices[i]; } } return ans; }Copy the code
The right reason
(1) This problem is limited to one transaction, so there is no need to solve it with dynamic programming
The best time to buy and sell stocks II
The title
Version 1 has an unlimited number of correct transactions
Public int maxProfit(int[] prices) {public int maxProfit(int[] prices) { Int [][] dp = new int[prices.length + 1][2]; // base case dp[0][1] = Integer.MIN_VALUE; For (int I = 1; i <= prices.length; I + +) {/ / the day I do not hold stock dp [I] [0] = math.h Max (dp [0], [I - 1] dp [1] + [I - 1] prices] [I - 1); / / the day I hold shares dp [I] [0] = math.h Max (dp [1], [I - 1] dp [0] - [I - 1] prices] [I - 1); } // return dp[prices.length][0]; }Copy the code
The right reason
(1) There is no need to consider the number of transactions
The best time to buy and sell stocks III
The title
Version 1 is the correct k = 2 case
Public static int maxProfit(int prices) {public static int maxProfit(int prices) {public static int maxProfit(int prices) {public static int maxProfit(int prices) { Int k = 2; int k = 2; int k = 2; int [][][] dp = new int[prices.length + 1][K + 1][2]; Dp [0][k][0] = 0; dp[0][k][0] = 0; Dp [0][k][1] = integer.min_value for (int k = 0; k <= K; k ++) { dp[0][k][1] = Integer.MIN_VALUE; } // In any day, if the number of trades is 0, it means that there is no trading, at this time, the maximum profit without holding the stock is 0, that is, dp[I][0][0] = 0; Dp [I][0][1] = intege.min_value; dp[I][0][1] = intege.min_value; for (int i = 0; i <= prices.length; i ++) { dp[i][0][1] = Integer.MIN_VALUE; } for (int I = 1; i <= prices.length; i ++) { for (int k = 1; k <= K; K + +) {/ / the first day, I the current trading times for k times, does not hold shares. Dp [I] [k] [0] = math.h Max (dp [k] [I - 1] [1] + prices] [I - 1, dp [I - 1] [k] [0]). Dp [I][k][1] = math. Max (dp[i-1][k-1][0] -prices [i-1], dp[i - 1][k][1]); }} return dp[prices.length][K][0];}} return dp[prices.length][K][0]; }Copy the code
The right reason
(1) On the basis of the template, let k = 2.
The best time to buy and sell stocks IV
The title
Version 1 is correct but there is no need to record the maximum value after each transaction
Public static int maxProfit(int k, int prices) {// maxProfit(int k, int prices) {// maxProfit(int k, int prices) {// maxProfit(int k, int prices) { If (k > prices.length / 2) {k = prices.length / 2; // dp[I][j][1] stands for day I, trades j times, and holds the maximum profit of the stock // dp[I][j][0] stands for day I, trades J times, Int [][][] dp = new int [prices.length + 1][k + 1][2]; // base case // dp[0][j][0] = 0 // dp[0][j][1] = integer.min_value for (int j = 0; j <= k; j ++) { dp[0][j][1] = Integer.MIN_VALUE; } // dp[I][0][0] = 0 // dp[I][0][1] = integer.min_value i <= prices.length; i ++) { dp[i][0][1] = Integer.MIN_VALUE; } // state transition int Max = 0; for (int i = 1; i <= prices.length; i ++) { for (int j = 1; j <= k; J + +) {/ / the number of day trading for j and I do not hold stock dp [I] [j] [0] = math.h Max (dp [I - 1) [j] [0], dp [j] [I - 1] [1] + prices] [I - 1); max = Math.max(dp[i][j][0], max); / / the number of day trading for j and I hold shares dp [I] [j] [1] = math.h Max (dp [I - 1) [j] [1], dp [I - 1] [1] [0] - prices] [I - 1); Return Max; return Max; return Max; return Max; }Copy the code
The right reason
(1) Record the appropriate number of k, and make reasonable reduction when K is too large
(2) There is no need to record the maximum value after each transaction, because according to the definition dp[][][] is always the maximum value and has been selected for optimization. Therefore, dp[prices.length][k][0] must be the maximum value, even though k may be used only once to achieve the optimal value. The number of subsequent transactions actually does not really settle the results, because it is preferred
Version 2 is correct and best written
Public static int maxProfit(int k, int prices) {// maxProfit(int k, int prices) {// maxProfit(int k, int prices) {// maxProfit(int k, int prices) { If (k > prices.length / 2) {k = prices.length / 2; // dp[I][j][1] stands for day I, trades j times, and holds the maximum profit of the stock // dp[I][j][0] stands for day I, trades J times, Int [][][] dp = new int [prices.length + 1][k + 1][2]; // base case // dp[0][j][0] = 0 // dp[0][j][1] = integer.min_value for (int j = 0; j <= k; j ++) { dp[0][j][1] = Integer.MIN_VALUE; } // dp[I][0][0] = 0 // dp[I][0][1] = integer.min_value i <= prices.length; i ++) { dp[i][0][1] = Integer.MIN_VALUE; } for (int I = 1; i <= prices.length; i ++) { for (int j = 1; j <= k; J + +) {/ / the number of day trading for j and I do not hold stock dp [I] [j] [0] = math.h Max (dp [I - 1) [j] [0], dp [j] [I - 1] [1] + prices] [I - 1); / / the number of day trading for j and I hold shares dp [I] [j] [1] = math.h Max (dp [I - 1) [j] [1], dp [I - 1] [1] [0] - prices] [I - 1); }} // According to the definition of the dp array, the maximum value is continuously passed backwards, because each value is selected preferentially, so even if the maximum number of transactions is 5 // the actual 2 transactions can get the maximum profit, Return dp[price.length][k][0]; return dp[price.length][k][0]; }Copy the code
The timing of buying and selling stocks includes the freeze period
The title
Version 1 correct number of transactions unlimited including freezing period
Public int maxProfit(int[] prices) {public int maxProfit(int[] prices) {public int maxProfit(int[] prices) {public int maxProfit(int[] prices) { Int [][] dp = new int[prices.length + 1][2]; Dp [0][0] = 0; dp[0] = 0; Dp [0][1] = integer.min_value dp[0][1] = integer.min_value dp[0][1] = integer.min_value For (int I = 1; i <= prices.length; I + +) {/ / the day I do not hold shares of dp [I] [0] = math.h Max (dp [1] + [I - 1] prices] [I - 1, dp [I - 1] [0]). Dp [I][1] = math. Max (dp[i-2][0] -prices [i-1], dp[i - 1][1]); } else { dp[i][1] = Math.max(dp[i - 1][0] - prices[i - 1] , dp[i - 1][1]); }} return dp[prices.length][0]; }Copy the code
The right reason
(1) The number of transactions is unlimited, so the number of transactions is not considered. The freezing period only affects the holding of stocks when I >= 2. Just notice the boundary