大家好,我是河海哥,专注于后端,如果可以的话,想做一名code designer而不是普通的coder,一起见证河海哥的成长,您的评论与赞是我的最大动力。
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
- 没有操作,不买入也不卖出 - 第一次买入 - 第一次卖出 - 第二次买入 - 第二次卖出那么就可以用
dp[i][j]
代表第i天,处于第j个状态时的收入。这边确实要注意,比如处于第二次买入的状态,并不一定说那一天必须是买入,也可能是之前发生过第二次买入,但是当天没有买入。比如[买,无,卖,无,无,无,买,无,无,i]那么i也是处于第二次买入的状态,因为之前已经出现过两次买入了,没有处于二次买的状态,那么i+1天就不能卖了。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); }
有几个注意点:
dp[1][0][2] = 0
; 第一天不持有股票,并且是第二次卖出的情况,也就是买,卖,买,卖这几个都发生了在同一天。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; }
这道题有点难,我自己的想法靠自己写无法ac,根据别人的评论,自己修改才最后ac,答案的那种方法,我确实想不到,用一个维度去列举每一天的所有状态。就当是一种解题的积累吧!加油呀,河海哥,至少保证以后做过的题会写就行,没做过的不会也没办法。您的评论和点赞是我续写的动力。如有错误,请指正,个人水平很有限。