Java description LeetCode, 123. Best Time to Buy and Sell Stock III

Keywords: Java leetcode

Hello, I'm hehaige. I focus on the back end. If I can, I want to be a code designer instead of an ordinary coder to witness the growth of hehaige. Your comments and praise are my biggest motivation.

1-1: title

You are given an array prices where prices[i] is the price of a given stock on the ith day.

Find the maximum profit you can achieve. You may complete at most two transactions.

Note: You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again).

Example 1:

Input: prices = [3,3,5,0,0,3,1,4]
Output: 6
Explanation: Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3.

Example 2:

Input: prices = [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are engaging multiple transactions at the same time. You must sell before buying again.

Example 3:

Input: prices = [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.

Example 4:

Input: prices = [1]
Output: 0

Constraints:

1 <= prices.length <= 105
0 <= prices[i] <= 105

Source: LeetCode
Link: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii

1-2: idea

  • Train of thought 1: there is the answer to question 2. The idea of holding stocks as a state. I wonder if I can add another dimension to represent the number of transactions, so as to ensure that the second transaction must be after the first transaction. Then I wrote a code according to this idea. Facts have proved that it is still relatively complex. Especially when initializing, if I don't think well, one can't ac.
  • Train of thought 2: there are five kinds of trading situations on a certain day
    - No operation, no buying or selling
    - First purchase
    - First sale
    - Second purchase
    - Second sale
    
    Then dp[i][j] can be used to represent the income in the j-th state on the i-th day. It should be noted here. For example, if you are in the state of second buying, it does not necessarily mean that you must buy on that day, or you may have bought for the second time before, but you didn't buy on that day. For example, [buy, no, sell, no, no, no, buy, no, no, I] then I is also in the second buying state, because I have bought twice before, and I cannot be sold in i+1 day.

1-3: idea1 code

public static int maxProfit(int[] prices) {
    int n = prices.length;
    // dp[i][j][k] represents whether to hold shares [0,1] on day i[1,n], and the maximum income of the k[0,2] transaction. It is specified that the number of transactions at the time of sale + 1
    int[][][] dp = new int[n + 1][2][3];

    for (int k = 0; k <= 2; k++) {
        dp[1][0][k] = 0;
        dp[1][1][k] = -prices[0];
    }

    for (int i = 2; i < n + 1; i++) {
        int price = prices[i - 1];
        for (int j = 0; j <= 2; j++) {
            // Transaction 0
            if (j == 0) {
                dp[i][0][j] = dp[i - 1][0][j];
            } else {
                // Not held today = max (not held yesterday, held yesterday + sold today). The held yesterday must be the last transaction, so here j is to be - 1
                dp[i][0][j] = Math.max(dp[i - 1][0][j], dp[i - 1][1][j - 1] + price);
            }
            // Today's holding = max (held yesterday, not held yesterday + bought today), not held yesterday, held today, is still a transaction, j don't move.
            dp[i][1][j] = Math.max(dp[i - 1][1][j], dp[i - 1][0][j] - price);
        }
    }
    List<Integer> list = new ArrayList<>();
    System.out.println(Arrays.deepToString(dp));
    for (int i = 0; i <= 1; i++) {
        for (int j = 0; j <= 2; j++) {
            // dp[n][0][0], dp[n][1][0], dp[n][0][1], dp[n][1][1], dp[n][0][2], dp[n][1][2]
            list.add(dp[n][i][j]);
        }
    }
    return Collections.max(list);
}

There are several points to note:

  • This code is simplified. You can list the dp state transition equation when j=0, 1 and 2, and then simplify it. I couldn't write it directly with j inner loop at the beginning.
  • Location of maximum value: there are skills to find the maximum value at last, but I didn't expect that the last time I sold it was the location of the maximum value.
  • Initialization: initialization is also a little difficult. At first, I felt that buying on the same day and selling on the same day did not meet the meaning of the topic. The topic said that buying on the same day could not be sold on the same day, which should not exist. However, after reading the answer, buying on the same day and selling on the same day will not affect the final result, such as dp[1][0][2] = 0; The first day did not hold stocks, and it was the second time to sell, that is, buy, sell, these all happened on the same day.

1-4: idea2 code

public static int maxProfit2(int[] prices) {
    int n = prices.length;
    // dp[i][j] stands for day I,
    // j represents the state of day i, five in total.
    // -0: no transaction on that day
    // -1: first purchase
    // -2: first sale
    // -3: second purchase
    // -4: second sale
    int[][] dp = new int[n + 1][5];

    // initialization
    for (int i = 0; i < dp[0].length; i++) {
        if (i % 2 == 1) {
            dp[1][i] = -prices[0];
        }
    }
    for (int i = 2; i < n + 1; i++) {
        int price = prices[i - 1];
        dp[i][0] = dp[i - 1][0];
        for (int j = 1; j <= 4; j++) {
            // j is odd
            if (j % 2 == 1) {
                dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1] - price);
            } else {
                dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1] + price);
            }
        }
//            //The first purchase on day i = max (no operation on that day, buy on that day), dp[i - 1][0] represents the maximum income without operation on the previous day. You can't buy for the first time if you are not in no operation state.
//            dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - price);
//            //The first sale on day i = max (no operation on that day, sell on that day), dp[i - 1][1] represents the maximum income in the buying state of the previous day. If you are not in the buying state, you cannot buy for the first time.
//            dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + price);
//            dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - price);
//            dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + price);
    }
    System.out.println(Arrays.deepToString(dp));
    return dp[n][4];
}

The notes here are detailed enough that I have written all the dp state transition equations. It should be easier to understand. Initialization is the same idea as before. We can use the idea of rolling array to give the second version:

public static int maxProfit3(int[] prices) {
    int n = prices.length;
    // dp[i][j] stands for day I,
    // j represents the state of day i, five in total.
    // -0: no transaction on that day
    // -1: first purchase
    // -2: first sale
    // -3: second purchase
    // -4: second sale
    int[][] dp = new int[n + 1][5];
    int nothing = 0;
    int buy1 = -prices[0];
    int sell1 = 0;
    int buy2 = -prices[0];
    int sell2 = 0;

    for (int i = 2; i < n + 1; i++) {
        int price = prices[i - 1];
        buy1 = Math.max(buy1, nothing - price);
        sell1 = Math.max(sell1, buy1 + price);
        buy2 = Math.max(buy2, sell1 - price);
        sell2 = Math.max(sell2, buy2 + price);
    }

    return sell2;
}

1-5: summary

This question is a little difficult. I can't write it by myself. According to other people's comments, I can only modify the final ac. I really can't think of the way to list all the states of each day in one dimension. Think of it as a problem-solving accumulation! Come on, brother Hehai, at least make sure that you can write the questions you have done in the future, and you can't do what you haven't done. Your comments and likes are my motivation to continue writing. If you have any mistakes, please correct them. Your personal level is very limited. 🤯

Posted by cristiano on Sat, 30 Oct 2021 20:21:34 -0700