1. 程式人生 > >[LeetCode] Best Time to Buy and Sell Stock with Transaction Fee 買股票的最佳時間含交易費

[LeetCode] Best Time to Buy and Sell Stock with Transaction Fee 買股票的最佳時間含交易費

Your are given an array of integers prices, for which the i-th element is the price of a given stock on day i; and a non-negative integer fee representing a transaction fee.

You may complete as many transactions as you like, but you need to pay the transaction fee for each transaction. You may not buy more than 1 share of a stock at a time (ie. you must sell the stock share before you buy again.)

Return the maximum profit you can make.

Example 1:

Input: prices = [1, 3, 2, 8, 4, 9], fee = 2
Output: 8
Explanation: The maximum profit can be achieved by:
  • Buying at prices[0] = 1
  • Selling at prices[3] = 8
  • Buying at prices[4] = 4
  • Selling at prices[5] = 9
The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8.

Note:

  • 0 < prices.length <= 50000.
  • 0 < prices[i] < 50000.
  • 0 <= fee < 50000.

又是一道股票交易的題,之前已經有過類似的五道題了,fun4LeetCode大神的帖子做了amazing的歸納總結,有時間的話博主也寫個總結。這道題跟Best Time to Buy and Sell Stock II其實最像,但是由於那道題沒有交易費的限制,所以我們就無腦貪婪就可以了,見到利潤就往上加。但是這道題有了交易費,所以當賣出的利潤小於交易費的時候,我們就不應該賣了,不然虧了。所以這道題還是還是得用動態規劃來做,按照fun4LeetCode大神的理論,本質其實是個三維dp陣列,由於第三維只有兩種情況,賣出和保留,而且第二維交易的次數在這道題中沒有限制,所以我們用兩個一維陣列就可以了,sold[i]表示第i天賣掉股票此時的最大利潤,hold[i]表示第i天保留手裡的股票此時的最大利潤。那麼我們來分析遞推公式,在第i天,如果我們要賣掉手中的股票,那麼此時我們的總利潤應該是前一天手裡有股票的利潤(不然沒股票賣毛啊),加上此時的賣出價格,減去交易費得到的利潤總值,跟前一天賣出的利潤相比,取其中較大值,如果前一天賣出的利潤較大,那麼我們就前一天賣了,不留到今天了。然後來看如果第i天不賣的利潤,就是昨天股票賣了的利潤然後今天再買入股票,得減去今天的價格,得到的值和昨天股票保留時的利潤相比,取其中的較大值,如果昨天保留股票的利潤大,那麼我們就繼續保留到今天,所以遞推時可以得到:

sold[i] = max(sold[i - 1], hold[i - 1] + prices[i] - fee);

hold[i] = max(hold[i - 1], sold[i - 1] - prices[i]);

參見程式碼如下:

解法一:

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

我們發現不管是賣出還是保留,第i天到利潤只跟第i-1天有關係,所以我們可以優化空間,用兩個變數來表示當前的賣出和保留的利潤,更新方法和上面的基本相同,就是開始要儲存sold的值,不然sold先更新後,再更新hold時就沒能使用更新前的值了,參見程式碼如下:

解法二:

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        int sold = 0, hold = -prices[0];
        for (int price : prices) {
            int t = sold;
            sold = max(sold, hold + price - fee);
            hold = max(hold, t - price);
        }
        return sold;
    }
};

類似題目:

參考資料: