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

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

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

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

题目链接:123.买卖股票的最佳时机III,难度:困难
【实现代码】

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.size() == 1) {
            return 0;
        }
        vector<vector<int>> dp(prices.size(), vector<int>(5, 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.size(); i++) {
            dp[i][1] = max(dp[i - 1][1], -prices[i]);
            dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
            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]);
        }
        return dp.back().back();
    }
};

【解题思路】

动态规划五部曲:

  1. 确定dp数组以及下标的含义:
    一天一共就有五个状态,
  • 0:没有操作 (其实我们也可以不设置这个状态)
  • 1:第一次持有股票
  • 2:第一次不持有股票
  • 3:第二次持有股票
  • 4:第二次不持有股票
    dp[i][j]中 i表示第i天,j为 [0 - 4] 五个状态,dp[i][j]表示第i天状态j所剩最大现金。
  1. 确定递推公式
    达到dp[i][1]状态,有两个具体操作:
  • 操作一:第i天买入股票了,那么dp[i][1] = dp[i-1][0] - prices[i]
  • 操作二:第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]也有两个操作:
  • 操作一:第i天卖出股票了,那么dp[i][2] = dp[i - 1][1] + prices[i]
  • 操作二:第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]);
  1. dp数组如何初始化:dp[0][0] = 0; dp[0][1] = -prices[0]; dp[0][2] = 0; dp[0][3] = -prices[0]; dp[0][4] = 0;
  2. 确定遍历顺序:递归公式其实已经可以看出,一定是从前向后遍历,因为dp[i],依靠dp[i - 1]的数值。
  3. 举例推导dp数组

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

题目链接:188.买卖股票的最佳时机IV,难度:困难
【实现代码】

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        if (prices.size() == 0) {
            return 0;
        }
        vector<vector<int>> dp(prices.size(), vector<int>(k * 2 + 1, 0));
        for (int i = 1; i <= k * 2; i += 2) {
            dp[0][i] = -prices[0];
        }
        for (int i = 1; i < prices.size(); i++) {
            for (int j = 1; j <= k * 2; j += 2) {
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - 1] - prices[i]);
                dp[i][j + 1] = max(dp[i - 1][j + 1], dp[i - 1][j] + prices[i]);
            }
        }
        return dp.back().back();
    }
};

【解题思路】

动态规划五部曲:

  1. 确定dp数组以及下标的含义:dp[i][j] :第i天的状态为j,所剩下的最大现金是dp[i][j],j的范围就定义为 2 * k + 1 ,除了0以外,偶数就是卖出,奇数就是买入。
  2. 确定递推公式
    达到dp[i][1]状态,有两个具体操作:
  • 操作一:第i天买入股票了,那么dp[i][1] = dp[i-1][0] - prices[i]
  • 操作二:第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]也有两个操作:
  • 操作一:第i天卖出股票了,那么dp[i][2] = dp[i - 1][1] + prices[i]
  • 操作二:第i天没有操作,沿用前一天卖出股票的状态,即:dp[i][2] = dp[i - 1][2]
    所以dp[i][2] = max(dp[i - 1][1] + prices[i], dp[i - 1][2])
  1. dp数组如何初始化:dp[0][j]当j为奇数的时候都初始化为 -prices[0]
  2. 确定遍历顺序:递归公式其实已经可以看出,一定是从前向后遍历,因为dp[i],依靠dp[i - 1]的数值。
  3. 举例推导dp数组

你可能感兴趣的:(算法基础,算法,动态规划,leetcode)