leetcode714-買賣股票的最佳時機含手續費

給定一個整數數組 prices,其中第 i 個元素代表了第 i 天的股票價格 ;非負整數 fee 代表了交易股票的手續費用。

你可以無限次地完成交易,但是你每次交易都需要付手續費。如果你已經購買了一個股票,在賣出它之前你就不能再繼續購買股票了。

返回獲得利潤的最大值。

示例 1:

輸入: prices = [1, 3, 2, 8, 4, 9], fee = 2
輸出: 8
解釋: 能夠達到的最大利潤:  
在此處買入 prices[0] = 1
在此處賣出 prices[3] = 8
在此處買入 prices[4] = 4
在此處賣出 prices[5] = 9
總利潤: ((8 - 1) - 2) + ((9 - 4) - 2) = 8.

注意:

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

一、思路

(一)貪心算法

思路很簡單,從後往前遍歷數組,遇到高價則將其設置爲出售價格,每次出售股票時,計算當前利潤與上一次利潤之和,再計算一下此次交易若以上一次的售價出售,所能得到的利潤,對比兩者的大小,選擇利潤高的方式出售。

C++代碼:

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
    	// 初始化售價、購買價、上一次出售價、如果以上一次售價出售所能得到的利潤
        int sale=prices[prices.size()-1], pre_sale=0, pur=0, fit;
        // 總利潤、當前這次交易的利潤、上一次交易的利潤
        int profit=0, cur_profit=0, pre_profit=0;
        for(int i=prices.size()-2; i >= 0; i--){
            if(prices[i] > sale){
                sale = prices[i];
                continue;
            }
            // 準備買賣
            pur = prices[i];
            cur_profit = sale - pur - fee;
            fit = pre_sale - pur - fee;
            if(fit > 0 && fit >= max(pre_profit + cur_profit, pre_profit)){
                    profit = profit - pre_profit + fit;
                    pre_profit = fit;
                    sale = pur;
                    continue;
            }
            if(cur_profit > 0){
                profit += cur_profit;
                pre_profit = cur_profit;
                pre_sale = sale;
                sale = pur;
            }
        }
        return profit;
    }
};

在這裏插入圖片描述

(二)動態規劃

1、狀態轉移框架

在這裏插入圖片描述
建立動態規劃表dp[i][j]dp[i][j]

  • i:表示第i天
  • j:表示當前股票的持有狀態,0表示沒有持有股票,1表示持有股票

動態規劃表dp[i][j]dp[i][j]的意義就很明顯了,就在第i天時,手裏持有股票(j=1)或者沒有持股(j=0)所能獲取的最大利潤。

除此之外,在這一天,還有3種操作可選:buy、sell、rest。

我們現在要做的就是遍歷所有可能的狀態,求出利潤最大的,那麼這裏的解題僞代碼可以寫成:

for 0 <= i < n:
	for j in {0, 1}:
		dp[i][j] = max{buy, sell, rest}

於是所求的答案爲:dp[n1][0]dp[n - 1][0]

4、狀態轉移方程

  • dp[i][0]=max(dp[i1][0],dp[i1][1]+prices[i]fee)dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee)
    這個方程表達的意思是:在第i天,手裏沒有持股,所能獲取的最大利潤爲dp[i][0]dp[i][0]
    那麼這個利潤是怎麼來的?這要從當前的狀態分析,因爲當前沒有持股,要麼昨天沒有持股,要麼昨天持股,但是今天賣掉了,這裏賣掉需要減去一個手續費纔是最終的利潤。
  • dp[i][1]=max(dp[i1][1],dp[i1][0]prices[i])dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i])
    這個方程表達的意思是:在第i天,手裏持股,所能獲取的最大利潤爲dp[i][1]dp[i][1]
    那麼這個利潤是怎麼來的?這要從當前的狀態分析,因爲當前持股,要麼昨天持股,要麼昨天沒有持股,但是今天買入了股票。

C++代碼:

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        if(prices.size() == 0 || prices.size() == 1)
            return 0;
        vector<vector<int>> dp(prices.size(), vector<int>(2, 0));
        // 初始化
        dp[0][1] = -prices[0];
        dp[1][0] = max(dp[0][0], dp[0][1] + prices[1] - fee);
        dp[1][1] = max(dp[0][1], dp[0][0] - prices[1]);
        // 狀態轉移
        for(int i=2; i < prices.size(); i++){
            dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i] - fee);
            dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i]);
        }
        return dp[prices.size() - 1][0];
    }
};

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章