代码随想录算法训练营第五十天 _ 动态规划_188.买卖股票最佳时机4、309.买卖股票的最佳时机含冷冻期、714.买卖股票的最佳时机含手续费。

学习目标:

动态规划五部曲:
① 确定dp[i]的含义
② 求递推公式
③ dp数组如何初始化
④ 确定遍历顺序
⑤ 打印递归数组 ---- 调试
引用自代码随想录!

60天训练营打卡计划!

学习内容:

188.买卖股票最佳时机4

  • 只能至多买卖k次且不能同时参与多笔交易。
  • 动态规划五步曲:
    ① 确定dp[i]的含义 :
    第 i 天 不操作 的最大金额dp[i][0],
    第 i天 第一次持有 这个股票的最大金额dp[i][1],
    第 i 天 第一次不持有 这个股票的最大金额dp[i][2],
    第 i 天 第k次持有 这个股票的最大金额dp[i][2k-1],
    第 i 天 第k次不持有 这个股票的最大金额dp[i][2k]。
    ② 求递推公式 :
    dp[i][0] = dp[i-1][0] ----- 为0
    dp[i][1] = max(dp[i-1][1], dp[i-1][0] - price[i])
    dp[i][2] = max(dp[i-1][2], dp[i-1][1] + price[i])
    dp[i][2k-1] = max(dp[i-1][2k-1], dp[i-1][2k-2] - price[i])
    dp[i][2k] = max(dp[i-1][2k], dp[i-1][2k-1] + price[i])
    ③ dp数组如何初始化 : dp[0][0] = 0 dp[0][1] = -price[0] dp[0][2] = 0
    dp[0][2k-1] = -price[0] dp[0][2k] = 0
    ④ 确定遍历顺序 : 从前向后
class Solution {
    public int maxProfit(int k, int[] prices) {
        int size = prices.length;
        // 使用 2k+1 是为了统一递推关系式
        int[][] dp = new int[size][2*k+1];
        // 初始化
        dp[0][0] = 0;
        for(int j = 1; j <= 2*k-1; j=j+2){
            dp[0][j] = -prices[0];
            dp[0][j+1] = 0;
        }
        // 循环逻辑
        // i是物品的数量
        for(int i = 1; i < size; i++){
            // j是买卖的次数
            for(int j = 1; j <= 2*k-1; j=j+2){
                // 买入
                dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-1] - prices[i]);
                // 卖出
                dp[i][j+1] = Math.max(dp[i-1][j+1], dp[i-1][j] + prices[i]);
            }
        }

        return dp[size-1][2*k];
    }
}

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

  • 在满足 卖出股票后,你无法在第二天买入股票 的条件下,你可以尽可能地完成更多的交易
  • 动态规划五步曲:
    ① 确定dp[i][j]的含义 :
    第i天持有这个股票的最大金额dp[i][0],
    第i个天保持卖出这个股票的最大金额dp[i][1],(买的时候没有冷冻期)
    第i天卖出这个股票的最大金额dp[i][2],
    第i个天冷冻期时这个股票的最大金额dp[i][3];
    ② 求递推公式 :
  • 持有状态:
  • 一直持有 / 第 i-1 天保持卖出,第i天买入 / 第 i-1 天冷冻期,第i天买入 三者取最大
    dp[i][0] = max(dp[i-1][0], max(dp[i-1][1]-price[i], dp[i-1][3]-price[i]))
  • 保持卖出:
  • 第 i-1 天保持卖出 / 第 i-1 天冷冻期 取最大
    dp[i][1] = max(dp[i-1][1], dp[i-1][3])
  • 卖出:
  • 第 i-1 天持有
    dp[i][2] = dp[i-1][0] + price[i]
  • 冷冻期:
  • 第 i-1 天卖出
    dp[i][3] = dp[i-1][2]
    ③ dp数组如何初始化 :
    dp[0][0] = -price[0]
    以下都是非法状态: — 可以通过递推关系回推:
    dp[0][1] = 0 dp[0][2] = 0 dp[0][1] = 0
    ④ 确定遍历顺序 : 从前向后
class Solution {
    public int maxProfit(int[] prices) {
        int size = prices.length;
        int[][] dp = new int[size][4];

        // 初始化
        dp[0][0] = -prices[0];
        // 以下都是非法状态,可以通过递推关系回推:
        dp[0][1] = 0;
        dp[0][2] = 0;
        dp[0][3] = 0;

        for(int i = 1; i < size; i++){
            // 持有状态的递归推导
            dp[i][0] = Math.max(dp[i-1][0], 
            Math.max(dp[i-1][1]-prices[i], dp[i-1][3]-prices[i]));
            // 保持持有状态的递归推导
            dp[i][1] = Math.max(dp[i-1][1], dp[i-1][3]);
            // 卖出状态的递归推导
            dp[i][2] = dp[i-1][0] + prices[i];
            // 冷冻期状态的递归推导
            dp[i][3] = dp[i-1][2];
        }

        return Math.max(dp[size-1][1], Math.max(dp[size-1][2], dp[size-1][3]));
    }
}

714.买卖股票的最佳时机含手续费

  • 要使用尽量少的交易次数获得最大利润
  • 动态规划五步曲:
    ① 确定dp[i][j]的含义 :
    第i天持有这个股票的最大金额dp[i][0],第i个天不持有这个股票的最大金额dp[i][1];
    第i-1天持有这个股票的最大金额dp[i-1][0],第i-1个天不持有这个股票的最大金额dp[i-1][1]。
    ② 求递推公式 :
  • 一直持有 / (第i-1必须未持有)第i天买入 取最大
    dp[i][0] = max(dp[i-1][0],dp[i-1][1] - price[i])
  • 一直未持有 / (第i-1必须持有)第i天卖出 取最大 , 其中fee指交易费
    dp[i][1] = max(dp[i-1][1], dp[i-1][0]+price[i] - fee)
    ③ dp数组如何初始化 : dp[0][0] = -price[0] dp[0][1] = 0
    ④ 确定遍历顺序 : 从前向后
class Solution {
    public int maxProfit(int[] prices, int fee) {
        int size = prices.length;
        int[][] dp = new int[size][2];

        // 初始化
        dp[0][0] = -prices[0];
        dp[0][1] = 0;

        // 递归逻辑
        for(int i = 1; i < size; i++){
            dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] - prices[i]);
            dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] + prices[i] - fee);
        }

        return dp[size-1][1];
    }
}

学习时间:

  • 上午两个半小时,整理文档半小时。

你可能感兴趣的:(刷题训练心得,算法,动态规划)