714. Best Time to Buy and Sell Stock with Transaction Fee(week8)

714. 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.

解題思路

顯然,這是一道動態(tài)規(guī)劃問題。對于這種問題而言,理解問題,并抽離出模型尤為關(guān)鍵。從題目可以知道,我們在每一天可以買、賣股票,或者什么都不做,但是約束是手里持有股票的股票數(shù)量最多為1(不能一次買多股,買之前必須先賣掉)。每次交易我們都需要付出一定的手續(xù)費。算出最后一天最大的利潤值。

先從最后一條規(guī)則入手:買賣股票需要付手續(xù)費,也就是說,如果在當(dāng)天同時買入又賣出股票,最后得到的利潤是負(fù)數(shù),顯然是不符合題目要求的,因此,我們可以得出每天的操作只能是:買一次、賣一次、什么都不做。另外,如果我們要在某一天賣掉股票,由于當(dāng)天買入立即賣出是不可行的,因此,在前一天,我們至少要持有股票。總結(jié)一下就是:

今天賣股票之后的利潤=前一天手握這支股票時的利潤+今天股票的價格-手續(xù)費

同理,如果今天我們需要買進股票:

今天買股票之后的利潤=前一天沒有股票時的利潤-今天股票的價格

最后,如果今天什么都不做:

今天持有股票的利潤=昨天持有股票的利潤
今天沒有股票的利潤=昨天沒有股票的利潤

從上述的式子,我們不難總結(jié)出:每天的狀態(tài)都分為是否持有股票兩種情況。題目要求我們求出最后一天(N)能獲得的最大利潤,我們不妨可以這樣考慮:

最后一天持有股票的利潤=前一天持有股票的利潤 | 前一天沒有股票的利潤-今天的價格
最后一天沒有股票的利潤=前一天沒有股票的利潤 | 前一天持有股票的利潤+今天的價格-手續(xù)費

假設(shè)這時候我們已經(jīng)知道了第N-1天沒有持有股票時利潤的最大值以及持有股票時利潤的最大值,那么最后一天的持有股票和沒有股票的利潤的最大值就是:

最后一天持有股票的利潤=MAX{前一天持有股票的利潤, 前一天沒有股票的利潤-今天的價格}
最后一天沒有股票的利潤=MAX{前一天沒有股票的利潤, 前一天持有股票的利潤+今天的價格-手續(xù)費}

第一天兩種狀態(tài)的利潤是已知的,因此,無論N取什么值,都能算出當(dāng)前N兩種狀態(tài)的最大值。由此總結(jié)出動態(tài)規(guī)劃的狀態(tài)轉(zhuǎn)移方程:

// 0代表沒有股票,1代表持有股票
profit[n][0] = max(profit[n-1][1] + price[n] - fee, profit[n-1][0])
profit[n][1] = max(profit[n-1][1], profit[n-1][0] - price[n])
return max(profit[n][0], profit[n][1])

一點優(yōu)化

由于我們并不需要返回每天的最大利潤,因此,記錄下每天的狀態(tài)和價格是沒有必要的,只需要記錄下前一天的兩個狀態(tài),并且在今天的迭代中分別替換掉他們即可。

時間復(fù)雜度分析

每天的計算量為O(1),遍歷一次即可得到結(jié)果,復(fù)雜度為O(n)。

空間復(fù)雜度分析

如果不做優(yōu)化,則需要開一個天數(shù)乘二大小的二維數(shù)組,復(fù)雜度為O(n)。優(yōu)化后復(fù)雜度為O(1).

源碼

class Solution {
public:
  int maxProfit(vector<int>& prices, int fee) {
    if (prices.size() == 0) {
      return 0;
    }
    int days = prices.size();
    int profits[50001][2] = {0};
    profits[0][1] = -prices[0];
    for (int i = 1; i < days; ++i) {
      profits[i][0] = max(profits[i-1][1] + prices[i] - fee, profits[i-1][0]);
      profits[i][1] = max(profits[i-1][1], profits[i-1][0] - prices[i]);
    }
    
    return profits[days-1][0] > profits[days-1][1] ? profits[days-1][0] : profits[days-1][1];
  }
};
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容