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

动态规划

解题思路

  1. leetcode🧑‍💻 122. 买卖股票的最佳时机Ⅱ 的基础上增加了 冷冻期

  2. 确定 dp 数组以及下标的含义dp[i][j] 表示天数 [0, i] 区间里,下标 i 这一天状态为 j 的时候能够获得的最大利润,其中:

    1. j = 0,表示当前不持股(冷冻期);
    2. j = 1,表示当前持股;
    3. j = 2,表示当前不持股(正常卖出);
  3. 确定递推公式

    1. dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][2]):当前不持股(冷冻期);
      1. dp[i - 1][0]:昨天不持股(冷冻期),今天不操作;
      2. dp[i - 1][2]:昨天不持股(正常卖出),今天不操作;
    2. dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]):当前持股;
      1. dp[i - 1][1]::昨天买入,今天不操作;
      2. dp[i - 1][0] - prices[i]:昨天不持股(冷冻期),今天买入;
    3. dp[i][2] = dp[i - 1][1] + prices[i]:表示当前不持股(正常卖出);
  4. 如何初始化 dp 数组

    1. 0 天不持有(冷冻期):dp[0][0] = 0
    2. 0 天持有:dp[0][1] = -prices[0]
    3. 0 天不持有(正常卖出):dp[0][2] = 0
  5. 确定遍历顺序:从递推公式可以看出 dp[i] 都是由 dp[i - 1] 推导出来的,那么一定是从前向后遍历;

  6. 举例推导 dp 数组:以 prices = [7, 1, 5, 3, 6, 4] 为例:

    索引 i = 0 索引 i = 1 索引 i = 2 索引 i = 3 索引 i = 4 索引 i = 5
    dp[i][0] 规定了今天 不持股(冷冻期) 0 0 0 4 4 5
    dp[i][1] 规定了今天 持股 -7 -1 -1 -1 -1 0
    dp[i][2] 规定了今天 不持股(正常卖出) 0 -6 4 2 5 3

复杂度

  1. 时间复杂度:O(n)

  2. 空间复杂度:状态压缩之前是 O(n),状态压缩后是 O(1)

实现代码

JavaScript
JavaScript
const maxProfit = (prices) => {
    const len = prices.length;
    if (prices.length < 2) {
        return 0;
    }

    let dp = new Array(len).fill(0).map(it => new Array(3).fill(0));
    dp[0][0] = 0;
    dp[0][1] = -prices[0];
    dp[0][2] = 0;

    for (let i = 1; i < len; i++) {
        // dp[i][0]: 手上不持有股票,并且今天不是由于卖出股票而不持股,拥有的现金数
        dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][2]);
        // dp[i][1]: 手上持有股票时,拥有的现金数
        dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
        // dp[i][2]: 手上不持有股票,并且今天是由于卖出股票而不持股,拥有的现金数
        dp[i][2] = dp[i - 1][1] + prices[i];
    }

    // 最后的结果由 「当前不持股(冷冻期)」、「当前不持股(正常卖出)」 推出,选择最大值
    return Math.max(dp[len - 1][0], dp[len - 1][2]);
};
const maxProfit = (prices) => {
    const len = prices.length;
    if (len < 2) {
        return 0;
    }

    let dp = new Array(2).fill(0).map(it => new Array(3).fill(0));
    dp[0][0] = 0;
    dp[0][1] = -prices[0];
    dp[0][2] = 0;

    for (let i = 1; i < len; i++) {
        dp[i % 2][0] = Math.max(dp[(i - 1) % 2][0], dp[(i - 1) % 2][2]);
        dp[i % 2][1] = Math.max(dp[(i - 1) % 2][1], dp[(i - 1) % 2][0] - prices[i]);
        dp[i % 2][2] = dp[(i - 1) % 2][1] + prices[i];
    }
    return Math.max(dp[(len - 1) % 2][0], dp[(len - 1) % 2][2]);
};

参考资料

  1. 卡尔:《代码随想录》

  2. liweiwei1419

打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 动态规划
    1. 1.1. 解题思路
    2. 1.2. 复杂度
    3. 1.3. 实现代码
  2. 2. 参考资料