代码随想录算法训练营第五十天|123.买卖股票的最佳时机III 、188.买卖股票的最佳时机IV

代码随想录算法训练营第五十天|123.买卖股票的最佳时机III 、188.买卖股票的最佳时机IV

买卖股票的最佳时机III

123.买卖股票的最佳时机III
文章讲解:https://programmercarl.com/0123.%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BAIII.html
题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iii/
视频讲解:https://www.bilibili.com/video/BV1WG411K7AR/

自己看到题目的第一想法

动态规划五步骤、使用持有和不持有来计算。

看完代码随想录之后的想法

因为最多有2次交持有和不持有,分了5种情况。
0.没有操作
1.第一次持有股票
2.第一次不持有股票
3.第二次持有股票
4.第二次不持有股票

dp[i][j]中 i表示第i天,j为 [0 - 4] 五个状态,dp[i][j]表示第i天状态j所剩最大现金。

自己实现过程中遇到哪些困难

看过代码随想录后自己实现了一下,ac了。

public int maxProfit(int[] prices) {
    // 确定dp数组以及下标含义:
    // 持有和不持有,分了5种情况。
    // 0. 没有操作
    // 1. 第一次持有股票
    // 2. 第一次不持有股票
    // 3. 第二次持有股票
    // 4. 第二次不持有股票
    // dp[i][j]中 i表示第i天,j为 [0 - 4] 五个状态,dp[i][j]表示第i天状态j所剩最大现金。
    int[][] dp = new int[prices.length][5];

    // 确定递推公式
    // dp[i][0]可以忽略 都没有操作 = 0
    // dp[i][1]第一次持有,可能是之前持有,可能是本次持有 dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0] - prices[i]);
    // dp[i][2]第一次不持有,可能是之前不持有,可能是本次不持有(本次不持有要上次持有的最大值+本次卖出) dp[i][2] = Math.max(dp[i-1][2],dp[i-1][1] + prices[i]);

    // 确定初始化值
    dp[0][0] = 0;
    dp[0][1] -= prices[0];
    dp[0][2] = 0;
    dp[0][3] -= prices[0];
    dp[0][4] = 0;

    // 确定遍历顺序,从小打大
    for(int i = 1; i < prices.length; i++){
        dp[i][0] = dp[0][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[prices.length - 1][4];
}

买卖股票的最佳时机IV

188.买卖股票的最佳时机IV
文章讲解:https://programmercarl.com/0188.%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BAIV.html
题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iv/
视频讲解:https://www.bilibili.com/video/BV16M411U7XJ/

自己看到题目的第一想法

和123.买卖股票的最佳时机III几乎一样,只是买具体买卖的次数用k来替换。
写代码的话就将k之前的情况分成2k+1种:
0. 没有操作
1.第一次持有股票
2.第一次不持有股票
3…第k次持有
4…第k次不持有
代码就把最佳时机III改吧改吧。

public int maxProfit(int k, int[] prices) {
    // 确定dp数组以及下标含义:
    // 持有和不持有,分了5种情况。
    // 0.没有操作
    // 1.第一次持有股票
    // 2.第一次不持有股票
    // 3......第k次持有
    // 4......第k次不持有
    // dp[i][j]中 i表示第i天,j为 [0 - 4] 五个状态,dp[i][j]表示第i天状态j所剩最大现金。
    int[][] dp = new int[prices.length][2*k + 1];

    // 确定初始化值
    for(int i = 0; i < 2*k + 1; i++){
        if(i % 2 == 1){
            dp[0][i] -= prices[0];
        }else{
            dp[0][i] = 0;
        }
    }

    // 确定遍历顺序,从小打大
    for(int i = 1; i < prices.length; i++){
        for(int j = 1; j < 2*k + 1; j++){
            if(j % 2 == 0){
                // 表示第j次不持有
                dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j - 1] + prices[i]);
            }else{
                // 表示第j次持有
                dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-1] - prices[i]);
            }
        }
    }
    return dp[prices.length - 1][2*k];
}

看完代码随想录之后的想法

自己实现过程中遇到哪些困难

照着上一题改吧改吧完成。

今日收获&学习时长

对于股票问题有了进一步的认识,股票问题核心是理解第i天的持有状态,通过持有状态去推导最优值。

你可能感兴趣的:(算法)