1、LeetCode123买卖股票的最佳时机III

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

本题要求至多买卖两次,这意味着可以买卖一次,可以买卖两次,也可以不买卖。

一天一共有5个状态

0:没有操作 

1:第一次持有股票

2:第一次不持有股票

3:第二次持有股票

4:第二次不持有股票

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

2、递推公式:

达到dp[i][1]状态,有两个具体操作:

        操作一:第i天买入股票了,那么dp[i][1] = dp[i-1][0] - prices[i]

        操作二:第i天没有操作,而是沿用前一天买入的状态,即:dp[i][1] = 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][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]);

3、初始化:

第0天没有操作,这个最容易想到,就是0,即:dp[0][0] = 0;

第0天做第一次买入的操作,dp[0][1] = -prices[0];

第0天做第一次卖出的操作,可以理解当天买入,当天卖出,所以dp[0][2] = 0;

第0天第二次买入操作,相当于第0天第一次买入了,第一次卖出了,然后再买入一次,dp[0][3] = -prices[0];

同理第二次卖出初始化dp[0][4] = 0;

4、遍历顺序:从前向后。

5、举例推导。

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

2、LeetCode188买卖股票的最佳时机IV

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

1、使用二维数组 dp[i][j] :第i天的状态为j,所剩下的最大现金是dp[i][j]

每天状态为:

0:没有操作 

1:第一次持有股票

2:第一次不持有股票

3:第二次持有股票

4:第二次不持有股票

......

本题至多可以买卖k次,每买卖一次,都对应了两天的状态,即第一天买入第二天卖出。

奇数买入偶数卖出。

所以 j 的范围一共可以有 2 * k + 1, 下标从0开始 最大达到2 * k。

2、递推公式:

上一题的递推公式为:

            dp[i][1] = max(dp[i-1][1], dp[i-1][0] - 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]);

本题奇数买入,偶数卖出。

            for (int j = 0; j < 2 * k; 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]);
            }

3、初始化:

dp[0][j]当j为奇数的时候都初始化为 -prices[0];

4、遍历顺序:从前向后。

5、举例推导。

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

        for (int i = 1; i < prices.size(); i++)
        {
            for (int j = 0; j < 2 * k; 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]);
            }
        }

        return dp[prices.size() - 1][2 * k];
    }
};
06-10 19:41