Files
leetcode-master/problems/0714.买卖股票的最佳时机含手续费.md
youngyangyang04 ac17ab9f16 Update
2020-12-17 15:42:21 +08:00

4.6 KiB
Raw Blame History

思路

本题相对于贪心算法122.买卖股票的最佳时机II,多添加了一个条件就是手续费。

贪心算法

贪心算法122.买卖股票的最佳时机II中使用贪心策略不用关系具体什么时候买卖,只要收集每天的正利润,最后稳稳的就是最大利润了。

而本题有了手续费,就要关系什么时候买卖了,因为只计算所获得利润,可能不足以手续费。

如果使用贪心策略,就是最低值买,最高值(如果算上手续费还盈利)就卖。

此时无非就是要找到两个点,买入日期,和卖出日期。

  • 买入日期:其实很好想,遇到更低点就记录一下。
  • 卖出日期:这个就不好算了,但也没有必要算出准确的卖出日期,只要当前价格大于(最低价格+费用),就可以收获利润,至于准确的卖出日期,就是连续收获利润区间里的最后一天。

所以我们在做收获利润操作的时候其实有两种情况:

  • 情况一:收获利润的这一天并不是收获利润区间里的最后一天(不是真正的卖出,相当于持有股票),所以后面要继续收获利润。
  • 情况二:收获利润的这一天是收获利润区间里的最后一天(相当于真正的卖出了),后面要重新记录最小价格了。

贪心算法C++代码如下:

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        int result = 0;
        int minPrice = prices[0]; // 记录最低价格
        for (int i = 1; i < prices.size(); i++) {
            // 买入
            if (prices[i] < minPrice) minPrice = prices[i]; // 情况二

            // 计算利润,可能有多次计算利润,最后一次计算利润才是真正意义的卖出
            if (prices[i] > minPrice + fee) {
                result += prices[i] - minPrice - fee;
                minPrice = prices[i] - fee; // 情况一,这一步很关键
            }
        }
        return result;
    }
};

从代码中可以看出对情况一的操作,因为如果还在收获利润的区间里,表示并不是真正的卖出,而计算利润每次都要减去手续费, 所以要让minPrice = prices[i] - fee;,这样在明天收获利润的时候,才不会多减一次手续费!

理解这里很关键,其实也是核心所在,很多题解关于这块都没有说清楚。

动态规划

我在「代码随想录」公众号里正在讲解贪心算法将在下一个系列详细讲解动态规划所以本题解先给出我的C++代码(带详细注释),感兴趣的同学可以自己先学习一下。

相对于贪心算法122.买卖股票的最佳时机II的动态规划解法中,只需要在计算卖出操作的时候减去手续费就可以了,代码几乎是一样的。

C++代码如下:

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        // dp[i][1]第i天持有的最多现金
        // dp[i][0]第i天持有股票所剩的最多现金
        int n = prices.size();
        vector<vector<int>> dp(n, vector<int>(2, 0));
        dp[0][0] -= prices[0]; // 持股票
        for (int i = 1; i < n; i++) {
            // 第i天持股票所剩最多现金 = max(第i-1天持股票所剩现金, 第i-1天持现金-买第i天的股票)
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
            // 第i天持有最多现金 = max(第i-1天持有的最多现金第i-1天持有股票所剩的最多现金+第i天卖出股票-手续费)
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee);
        }
        return max(dp[n - 1][0], dp[n - 1][1]);
    }
};

当然可以对空间经行优化,因为当前状态只是依赖前一个状态。

C++ 代码如下:

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        int n = prices.size();
        int holdStock = (-1) * prices[0]; // 持股票
        int saleStock = 0; // 卖出股票
        for (int i = 1; i < n; i++) {
            int previousHoldStock = holdStock;
            holdStock = max(holdStock, saleStock - prices[i]);
            saleStock = max(saleStock, previousHoldStock + prices[i] - fee);
        }
        return saleStock;
    }
};

细心的同学可能发现在计算saleStock的时候 使用的已经是最新的holdStock了理论上应该使用上一个状态的holdStock即i-1时候的holdstock但是