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

状态机dp,可以参考LeetCode188. 买卖股票的最佳时机 IV

我们有两个状态,当前交易的天数i和当前是否持有股票,我们用一个二维数组dp[n][2]表示各个状态所能获得的最大收益(其中n为prices数组的大小,表示交易的天数)。
比如dp[i][0]表示第i天(i从0开始),当前不持有股票(第二维0表示不持有股票,1表示持有股票)所能获得的最大收益。
dp[i][1]表示第i天(i从1开始),当前持有股票所能获得的最大收益。

我们考虑一个不持有股票的状态dp[i][0], 不持有股票有两种情况:(1)前一天也不持有股票,然后今天啥也没做,这种情况下收益和前一天是相同的。这种情况下我们有:dp[i][0] = dp[i - 1][0];
(2)前一天持有股票,今天卖掉了,这种情况下我们有:dp[i][0] = dp[i - 1][1] + prices[i]; 其中加prices[i]表示卖掉股票获得了收益。
由于dp数组表示的是某个状态下的最大收益,因此我们需要对上面两种状态取一个max,所以我们有: dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);

我们考虑一个持有股票的状态dp[i][1], 持有股票也有两种情况:(1)前一天就持有了股票,然后今天没有操作,这种情况下收益和前一天是相同的。这种情况下我们有:dp[i][1] = dp[i - 1][1];
(2)前一天不持有股票,今天买了一只股票,这种情况下我们有:dp[i][1] = dp[i - 1][1] - prices[i] - fee; 其中减去prices[i]和fee表示第i天以prices[i]的价格买了股票,并交了价格为fee
的手续费。
由于dp数组表示的是某个状态下的最大收益,因此我们需要对上面两种状态取一个max,所以我们有:dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i] - fee);

现在我们有了状态转移方程,由于状态转移的过程中计算dp[i][]需要用到状态dp[i - 1][],当i为0时会导致数组越界,所以我们需要对边界情况特殊处理一下。

dp[0][0]表示第0天,不持有股票所能获得的最大收益,显然dp[0][0] = 0;
dp[0][1]表示第0天,持有股票所能获得的最大收益,显然第0天要持有股票只能第0天买了,要交第0天股票的价格,还有手续费。所以我们有dp[0][1] = -prices[0] - fee;

有了状态表示、处理了递归边界、推导出了状态转移方程,就可以开始状态转移了。

最后的答案就是dp[n - 1][0],表示最后一天,不持有股票所能获得的最高收益。
为什么不是dp[n - 1][1]呢?因为买股票需要成本(股票本身的价格以及手续费),股票卖出去能够获得收入,所以dp[n - 1][0]的值大于dp[n - 1][1]。

代码如下:

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        int n = prices.size();
        vector<vector<int>> dp(n, vector<int>(2));
        for(int i = 0; i < n; ++i) {
            if(i == 0) {                        //递推边界
                dp[i][0] = 0;
                dp[i][1] = -prices[i] - fee;
                continue;
            }
            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[n - 1][0];
    }
};
原文地址:https://www.cnblogs.com/linrj/p/13460609.html