【LeetCode】309.最佳买卖股票时机含冷冻期

86 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第24天,点击查看活动详情

题目

给定一个整数数组prices,其中第 prices[i] 表示第 i 天的股票价格 。

设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):

卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1

输入: prices = [1,2,3,0,2]
输出: 3 
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]

示例 2

输入: prices = [1]
输出: 0

提示

  • 1 <= prices.length <= 5000
  • 0 <= prices[i] <= 1000

题解

思路

我们考虑第 i 天可能采取的操作,很明显有三种,即不操作,操作(分为买入和卖出),但仔细想,不操作又能根据当天是否持有股票分为两种,即持有股票但不操作,不持有股票也不操作。所以我们把第 i 天可以采取的操作分成四种,即

  1. 持有股票但不操作,记作操作 A
  2. 不持有股票也不操作,记作操作 B
  3. 买入股票(换句话说,不持有股票要操作),记作 C
  4. 卖出股票(换句话说,持有股票要操作),记作 D 下面我们来考虑不同操作在第 i 天到第 (i+1) 天的状态转移,
  5. 如果第 i 天持有股票不操作,则第 (i+1) 天可以继续持有股票不操作,或者将持有的股票卖掉,即 A --> {A、D}
  6. 如果第 i 天不持有股票也不操作,则第 (i+1) 天可以继续不持有也不操作,或者买入股票,即 B --> {B、C}
  7. 如果第 i 天买入股票,则第 (i+1) 天可以继续持有股票不操作,或者将股票卖掉,即 C --> {A、D}
  8. 如果第 i 天卖掉了股票,则因为冷冻期的存在,第 (i+1) 天不能进行操作(不持有股票),即 D --> {B} 总结一下,{A、C} --> A,{B、D} --> B,{B} --> C,{A、C} --> D, 我们对 n=1 和 n=2 两种情况特殊处理,当 n>2 时,考虑第二天 (i = 1) 可以采取的操作及对应的收益,
  9. 第二天持有股票但不操作,说明第一天已经买入股票,所以到第二天的收益为 -prices[0]
  10. 第二天不持有股票但不操作,说明第一天没有买入股票,所以到第二天收益为 0
  11. 第二天买入股票,说明第一天没有操作过,所以到第二天的收益为 -prices[1]
  12. 第二天卖出股票,说明第一天已经买入了股票,说以到第二天的收益为 prices[1]-prices[0]

代码

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        if (n <= 1) return 0;
        if (n == 2) return max(0, prices[1] - prices[0]);

        vector<vector<int>> dp(n, vector<int>(4));
        // 初始状态
        dp[1][0] = -prices[0]; // 第二天是持有股票状态,但不操作,说明第一天买入了股票
        dp[1][1] = 0; // 第二天是不持有股票状态,但不操作,说明第一天也没有买入股票
        dp[1][2] = -prices[1]; // 第二天买入股票,说明第一天其实没有操作过
        dp[1][3] = prices[1] - prices[0]; // 第二天卖出股票,说明第一天肯定买入了股票
        for (int i = 2; i < n; ++i) {
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][2]);
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][3]);
            dp[i][2] = dp[i - 1][1] - prices[i];
            dp[i][3] = max(dp[i - 1][0], dp[i - 1][2]) + prices[i];
        }
        // 最后一天的最大收益只需在完成后不持有股票的两个操作里选择较大者
        return max(dp[n - 1][3], dp[n - 1][1]);
    }
};

结语

业精于勤,荒于嬉;行成于思,毁于随。