Day51 | 309.最佳买卖股票时机含冷冻期, 714.买卖股票的最佳时机含手续费

Day51 | 309.最佳买卖股票时机含冷冻期, 714.买卖股票的最佳时机含手续费

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

LeetCode题目:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-cooldown/

  买卖股票包含冷冻期的情况下,不持有股票的情况下存在三种不同的状态:(1)持续不持有股票且度过冷冻期。(2)不持有股票且正在冷冻期。(3)当天准备不持有股票,即执行卖出股票操作。三种情况只有(1)和(2)状态可以在第二天执行股票的买入操作。因此通过两种状态和持有股票前一天的状态来进行计算。

  所以,持有股票的递推公式应该由三个状态(持续不持有股票、不持有股票正在冷冻期、持有股票)递推所得到的最大值来获取:dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][1] - prices[i], dp[i - 1][3] - prices[i]));,而其他三个状态则由本身进行递推,当持续不持有股票且度过冷冻期时,它的最大收益应当从度过冷冻期的持有股票状态获取,即从上一天的状态(1)和状态(2)对比获取。当不持有股票且正在冷冻期时,它的上一个状态应该是当天准备不持有股票的时候,因此直接从上一天的状态(3)获取。当当天准备不持有股票时,应该卖出股票,即利用上一天持有股票的状态进行计算即可。

  因此,由以上推理,至少需要初始化四个状态才能完成上述状态转移。

  代码如下:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        vector<vector<int>> dp(prices.size(), vector<int>(4, 0));
        dp[0][0] = 0 - prices[0];//持有股票
        dp[0][1] = 0;//持续未持有股票
        dp[0][2] = 0;//卖出股票
        dp[0][3] = 0;//冷冻期
        for (int i = 1; i < prices.size(); i++) {
            dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][1] - prices[i], dp[i - 1][3]  - prices[i]));
            dp[i][1] = 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 max(max(dp[prices.size() - 1][1],dp[prices.size() - 1][2]),dp[prices.size() - 1][3]);
    }
};

  此外,利用打家劫舍的间隔思想似乎也可以做出来。已知冷冻期时不可以进行买入操作,且dp数组反应的是当前天数时最大收益的状态。那么我们可以推出,既然冷冻期无法买入,那么一定也不会进行卖出状态的更新。那么冷冻期结束后的买入操作,一定是通过两天前的未持有股票状态所推导得出的。

  因为是表示状态的方程,所以每次递推后,如果数值不改变,就可以看做是解法一中的持续未持有股票操作。

  对于未持有时候的操作,因为买入后是没有冻结期的,所以每次卖出一定是要依赖于昨天的持有股票状态进行更新。因为维护的是状态量,所以不用考虑昨天是否进行过卖出的操作,或者说,递推公式本身就是为了替换掉昨天产生的最大值,以说明当前的持有股票存在有更高收益的解法。并将状态传递给后一天的持有股票递推公式。

  不过需要注意此时需要两天才能完成初始化,代码如下:

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

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

LeetCode题目:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/

  与问题二很相似,只不过是在计算利润的时候包含手续费即可。但注意,如果在获取股票的时候计算手续费,记得在初始化的时候就要包含手续费,否则相当于第一次买入操作不需要手续费,带来错误。

  最终代码如下:

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

你可能感兴趣的:(数据结构,动态规划,leetcode,算法)