编程语言
首页 > 编程语言> > Java描述 LeetCode,123. Best Time to Buy and Sell Stock III(买卖股票的时机III)

Java描述 LeetCode,123. Best Time to Buy and Sell Stock III(买卖股票的时机III)

作者:互联网

大家好,我是河海哥,专注于后端,如果可以的话,想做一名code designer而不是普通的coder,一起见证河海哥的成长,您的评论与赞是我的最大动力。

1-1:题目

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii

1-2:idea

1-3:idea1代码

public static int maxProfit(int[] prices) {
    int n = prices.length;
    // dp[i][j][k] 代表第i[1,n]天,是否持有股票[0,1],第k[0,2]次交易的最大收入,规定卖出的时候交易次数+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++) {
            // 第0次交易
            if (j == 0) {
                dp[i][0][j] = dp[i - 1][0][j];
            } else {
                // 今天不持有 = max(昨天不持有,昨天持有状态+今天卖出),昨天持有状态一定是上一次交易,所以这边j是要-1的
                dp[i][0][j] = Math.max(dp[i - 1][0][j], dp[i - 1][1][j - 1] + price);
            }
            // 今天持有 = max(昨天持有,昨天不持有状态+今天买入),昨天不持有状态,今天持有,仍然是一个交易之下,j不用动。
            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);
}

有几个注意点:

1-4:idea2代码

public static int maxProfit2(int[] prices) {
    int n = prices.length;
    // dp[i][j]代表第i天,
    // j代表第i天第状态,共五种。
    // - 0:当天无交易
    // - 1:第一次买入
    // - 2:第一次卖出
    // - 3:第二次买入
    // - 4:第二次卖出
    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);
            }
        }
//            // 第i天第一次买入 = max(当天无操作,当天买入),dp[i - 1][0]代表前一天处于无操作下的最大收入。不处于无操作状态,就不能第一次买入。
//            dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - price);
//            // 第i天第一次卖出 = max(当天无操作,当天卖出),dp[i - 1][1]代表前一天处于买入状态下的最大收入。不处于买入状态,就不能第一次买入。
//            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];
}

这里注释足够细致,我把所有的dp状态转移方程都写出来了。应该比较好理解了。初始化,也是之前的那个思路,我们可以用滚动数组的思想,给出第二版:

public static int maxProfit3(int[] prices) {
    int n = prices.length;
    // dp[i][j]代表第i天,
    // j代表第i天第状态,共五种。
    // - 0:当天无交易
    // - 1:第一次买入
    // - 2:第一次卖出
    // - 3:第二次买入
    // - 4:第二次卖出
    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:总结

这道题有点难,我自己的想法靠自己写无法ac,根据别人的评论,自己修改才最后ac,答案的那种方法,我确实想不到,用一个维度去列举每一天的所有状态。就当是一种解题的积累吧!加油呀,河海哥,至少保证以后做过的题会写就行,没做过的不会也没办法。您的评论和点赞是我续写的动力。如有错误,请指正,个人水平很有限。

标签:Sell,Buy,int,max,price,Math,prices,III,dp
来源: https://blog.csdn.net/qq_41376740/article/details/121061034