2020-12-17 买卖股票的最佳时机(含手续费)

题目



题解

动态规划

在每一天结束后,账户有两种股票的持有状态:持有与不持有。我们使用\(dp[i][0]\)表示第\(i+1\)天结束后不持有股票的情况下的当前最大收益,使用\(dp[i][1]\)表示第\(i+1\)天结束后持有股票的情况下的当前最大收益。

  • 对于\(dp[i][0]\),即第\(i+1\)天结束后不持有股票,若前一天不持有股票,则dp[i][0] = dp[i-1][0];若前一天持有股票,则表示当天将股票卖出,dp[i][0] = dp[i-1][1]+precise[i]-fee,二者选其大。

\[dp[i][0] = max(dp[i-1][0], dp[i-1][1]+precise[i]-fee) \]

  • 对于\(dp[i][1]\),即第\(i+1\)天结束后持有股票,若前一天不持有股票,则表示当天买入,dp[i][1] = dp[i-1][0]-precise[i];若前一天持有股票,则dp[i][1] = dp[i-1][1],二者选其大。

\[dp[i][1] = max(dp[i-1][1], dp[i-1][0]-precise[i]) \]

在本题中,由于当天的状态只与前一天的状态有关,所以不需要维护\(dp\)这样一个二维数组,而只需使用两个变量\(sell\)\(buy\)来记录状态即可。

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

        return sell;
    }
};

贪心法

\(buy\)表示在利益最大的前提下,最低的买入价格+交易费用;初始情况buy = precise[0] + fee,在向后遍历的过程中可能遇到这几种情况:

  • buy > precise[i]+fee:即找到了更低的买入价格,使用precise[i]+fee替换buy
  • buy < precise[i]:即以当前价格卖出,即使加上手续费仍能盈利,应果断卖出。但是后续可能出现更高的股价,这时可以将buy置为precise[i],若后续出现更高的价格,比如下一天出现更高的价格,则profit += precise[i+1] - precise[i];
  • precise[i] + fee > buy > precise[i]:这种情况既不能卖出,也不能以更低的价格买入,不做操作。
class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        int profit = 0;
        int buy = prices[0] + fee;
        int len = prices.size();
        for (int i =1; i < len; ++i) {
            if (buy > prices[i] + fee) {
                buy = prices[i] + fee;
            } else {
                if (buy < prices[i]) {
                    profit += prices[i] - buy;
                    buy = prices[i];
                }
            }
        }

        return profit;
    }
};

总结

一看到题目就知道是动态规划,使用贪心也有机会解出来,但就是想不出状态转换方程,贪心的一些小细节也拿捏不准,最后还是看了题解才能做出来。

posted @ 2020-12-17 20:33  刷书狂魔  阅读(115)  评论(0编辑  收藏  举报
总访问: counter for blog 次