• 【动态规划】123. 买卖股票的最佳时机 III、188. 买卖股票的最佳时机 IV


    提示:努力生活,开心、快乐的一天


    123. 买卖股票的最佳时机 III

    题目链接:123. 买卖股票的最佳时机 III

    💡解题思路

    1. 动规五部曲:
    • 确定dp数组以及下标的含义:一天一共就有五个状态,
      0: 没有操作 (其实我们也可以不设置这个状态)
      1: 第一次持有股票
      2: 第一次不持有股票
      3: 第二次持有股票
      4: 第二次不持有股票
      dp[i][j]中 i表示第i天,j为 [0 - 4] 五个状态,dp[i][j]表示第i天状态j所剩最大现金。dp[i][1],表示的是第i天,买入股票的状态,并不是说一定要第i天买入股票
    • 确定递推公式:
      达到dp[i][1]状态,有两个具体操作
      1、 操作一:第i天买入股票了,那么dp[i][1] = dp[i-1][0] - prices[i]
      2、 操作二:第i天没有操作,而是沿用前一天买入的状态,即:dp[i][1] = dp[i - 1][1]
      dp[i][1] = max(dp[i-1][0] - prices[i], dp[i - 1][1])
      同理dp[i][2]也有两个操作:
      1、操作一:第i天卖出股票了,那么dp[i][2] = dp[i - 1][1] + prices[i]
      2、操作二:第i天没有操作,沿用前一天卖出股票的状态,即:dp[i][2] = dp[i - 1][2]
      dp[i][2] = max(dp[i - 1][1] + prices[i], dp[i - 1][2])
      同理可推出剩下状态部分:
      dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
      dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
    • dp数组如何初始化:
      第0天没有操作,dp[0][0] = 0;
      第0天做第一次买入的操作,dp[0][1] = -prices[0];
      第0天做第一次卖出的操作,dp[0][2] = 0;
      第0天第二次买入操作,dp[0][3] = -prices[0];
      第0天第二次卖出初始化dp[0][4] = 0;
    • 确定遍历顺序:从递推公式可以看出dp[i]都是由dp[i - 1]推导出来的,那么一定是从前向后遍历。
    • 举例推导dp数组:按照递推公式推导一下做推导,如果发现结果不对,就把dp数组打印出来
      在这里插入图片描述

    🤔遇到的问题

    1. 很难,每一步都要一步一步梳理

    💻代码实现

    动态规划

    var maxProfit = function (prices) {
        //0:没有操作 (其实我们也可以不设置这个状态)
        //1:第一次持有股票
        //2:第一次不持有股票
        //3:第二次持有股票
        //4:第二次不持有股票
        let len = prices.length
        const dp = new Array(len).fill(0).map(x => new Array(5).fill(0));
        dp[0][1] = -prices[0]
        dp[0][3] = -prices[0]
        for (let i = 1; i < len; i++) {
            dp[i][0] = dp[i - 1][0];
            dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i])
            dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
            dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
            dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
        }
        return dp[len - 1][4]
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    🎯题目总结

    达到dp[i][1]状态,有两个具体操作
    1、 操作一:第i天买入股票了,那么dp[i][1] = dp[i-1][0] - prices[i]
    2、 操作二:第i天没有操作,而是沿用前一天买入的状态,即:dp[i][1] = dp[i - 1][1]
    dp[i][1] = max(dp[i-1][0] - prices[i], dp[i - 1][1])
    同理dp[i][2]也有两个操作:
    1、操作一:第i天卖出股票了,那么dp[i][2] = dp[i - 1][1] + prices[i]
    2、操作二:第i天没有操作,沿用前一天卖出股票的状态,即:dp[i][2] = dp[i - 1][2]
    dp[i][2] = max(dp[i - 1][1] + prices[i], dp[i - 1][2])
    同理可推出剩下状态部分:
    dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
    dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]);


    188. 买卖股票的最佳时机 IV

    题目链接:188. 买卖股票的最佳时机 IV

    💡解题思路

    1. 动规五部曲:
    • 确定dp数组以及下标的含义:二维数组 dp[i][j] :第i天的状态为j,所剩下的最大现金是dp[i][j]
      0: 没有操作 (其实我们也可以不设置这个状态)
      1: 第一次持有股票
      2: 第一次不持有股票
      3: 第二次持有股票
      4: 第二次不持有股票
      。。。
      规律:除了0以外,偶数就是卖出,奇数就是买入
    • 确定递推公式:
      达到dp[i][1]状态,有两个具体操作
      1、 操作一:第i天买入股票了,那么dp[i][1] = dp[i-1][0] - prices[i]
      2、 操作二:第i天没有操作,而是沿用前一天买入的状态,即:dp[i][1] = dp[i - 1][1]
      dp[i][1] = max(dp[i-1][0] - prices[i], dp[i - 1][1])
      同理dp[i][2]也有两个操作:
      1、操作一:第i天卖出股票了,那么dp[i][2] = dp[i - 1][1] + prices[i]
      2、操作二:第i天没有操作,沿用前一天卖出股票的状态,即:dp[i][2] = dp[i - 1][2]
      dp[i][2] = max(dp[i - 1][1] + prices[i], dp[i - 1][2])
    for (let j = 0; j < 2 * k - 1; j += 2) {
        dp[i][j + 1] = max(dp[i - 1][j + 1], dp[i - 1][j] - prices[i]);
        dp[i][j + 2] = max(dp[i - 1][j + 2], dp[i - 1][j + 1] + prices[i]);
    }
    
    • 1
    • 2
    • 3
    • 4
    • dp数组如何初始化:
      第0天没有操作,dp[0][0] = 0;
      第0天做第一次买入的操作,dp[0][1] = -prices[0];
      第0天做第一次卖出的操作,dp[0][2] = 0;
      第0天第二次买入操作,dp[0][3] = -prices[0];
      第0天第二次卖出初始化dp[0][4] = 0;
      同理可以推出dp[0][j]当j为奇数的时候都初始化为 -prices[0]
    for (let j = 1; j < 2 * k; j += 2) {
        dp[0][j] = -prices[0];
    }
    
    • 1
    • 2
    • 3
    • 确定遍历顺序:从递推公式可以看出dp[i]都是由dp[i - 1]推导出来的,那么一定是从前向后遍历。
    • 举例推导dp数组:按照递推公式推导一下做推导,如果发现结果不对,就把dp数组打印出来在这里插入图片描述
      最后一次卖出,一定是利润最大的,dp[prices.size() - 1][2 * k]即红色部分就是最后求解。

    🤔遇到的问题

    1. 买卖次数非定值的时候,最大价值的规律也是有迹可循的

    💻代码实现

    动态规划

    const maxProfit = (k,prices) => {
        if (prices == null || prices.length < 2 || k == 0) {
            return 0;
        }
        let dp = Array.from(Array(prices.length), () => Array(2*k+1).fill(0));
        for (let j = 1; j < 2 * k; j += 2) {
            dp[0][j] = 0 - prices[0];
        }
        for(let i = 1; i < prices.length; i++) {
            for (let j = 0; j < 2 * k; j += 2) {
                dp[i][j+1] = Math.max(dp[i-1][j+1], dp[i-1][j] - prices[i]);
                dp[i][j+2] = Math.max(dp[i-1][j+2], dp[i-1][j+1] + prices[i]);
            }
        }
        return dp[prices.length - 1][2 * k];
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    🎯题目总结

    买卖次数非定值的时候,最大价值的规律也是有迹可循的

    🎈今日心得

    很难,似懂非懂,半知半解的状态

  • 相关阅读:
    面向对象之抽象类的认识 - (java语法)
    LeetCode简单题之判断两个事件是否存在冲突
    学内核之五:问题一,关于上下文切换
    升级降级苹果手机iOS系统工具iMazing2024
    基于Restful的WebService
    iOS上架App Store的全攻略
    我又又又把Kubernetes整理了一次
    Spring MVC异常处理
    Windows C++ 环境下 eigen、osqp、osqp-eigen安装教程
    Matlab:非线性函数的运算
  • 原文地址:https://blog.csdn.net/lx1234lj/article/details/133816771