leetcode【309】Best Time to Buy and Sell Stock with Cooldown【c++版本,時間100%,空間O(1)】

問題描述:

Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times) with the following restrictions:

  • You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
  • After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day)

Example:

Input: [1,2,3,0,2]
Output: 3 
Explanation: transactions = [buy, sell, cooldown, buy, sell]

源碼:

有時間要來寫一個股票類的專題,這傢伙,出現了一次又一次,這侮辱我呢。先給個連接吧:

leetcode【121】Best Time to Buy and Sell Stock

leetcode【122】Best Time to Buy and Sell Stock II

leetcode【123】Best Time to Buy and Sell Stock III

leetcode【188】【tag DP】Best Time to Buy and Sell Stock IV

不瞎扯皮了,還是看題目吧。這題小編想了很久沒想出來,也嘗試用之前的那樣global和local那樣的方法,可惜失敗了。最後翻了一下網上大神的博客。看到了一個思路:

多了一個cooldown的條件,就變得麻煩多了。這題是一個多階段優化問題,首先範圍縮小到廣搜,貪心或者動規。因爲每步之間互相牽連,貪心顯然不行。廣搜固然可以,不過是O(2^n)複雜度,所以我們先考慮用動規。

對於每一天,有三種動作,buy, sell, cooldown, sell 和 cooldown 可以合併成一種狀態,因爲手裏最終沒有股票。最終需要的結果是 sell,即手裏股票賣了獲得最大利潤。我們可以用兩個數組來記錄當前持股和未持股的狀態,令sell[i] 表示第i天未持股時,獲得的最大利潤,buy[i]表示第i天持有股票時,獲得的最大利潤。

對於sell[i],最大利潤有兩種可能,一是今天沒動作跟昨天未持股狀態一樣,二是今天賣了股票,所以狀態轉移方程如下:

sell[i] = max{sell[i - 1], buy[i-1] + prices[i]}

對於buy[i],最大利潤有兩種可能,一是今天沒動作跟昨天持股狀態一樣,二是前天賣了股票,今天買了股票,因爲 cooldown 只能隔天交易,所以今天買股票要追溯到前天的狀態。狀態轉移方程如下:

buy[i] = max{buy[i-1], sell[i-2] - prices[i]}

最終我們要求的結果是sell[n - 1],表示最後一天結束時,手裏沒有股票時的最大利潤。

這個算法的空間複雜度是O(n)

class Solution {
public:
	int maxProfit(vector<int>& prices) {
		int result=0, n=prices.size();
		if (n<2)    return 0;
        vector<int> sell(n, 0), buy(n, 0);
        sell[0] = 0;
        buy[0] = -prices[0];
        for (int i=1; i<n; i++){
            int diff = prices[i]-prices[i-1];
            sell[i] = max(sell[i-1]+diff, buy[i-1]+prices[i]);
            if (i>1)    buy[i] = max(sell[i-2]-prices[i], buy[i-1]-diff);
            else        buy[i] = buy[i-1]-diff;
            result = max(result, max(sell[i], buy[i]));
        }
        return result;
	}
};

但是既然他只用到了狀態方程的前兩項,那麼是一定可以優化到空間爲O(1)的。結果如下

時間100%,空間77%。非常高效。

class Solution {
public:
	int maxProfit(vector<int>& prices) {
		int result=0, n=prices.size();
		if (n<2)    return 0;
        int sell=0, buy=-prices[0], pre_sell=0;
        for (int i=1; i<n; i++){
            int diff = prices[i]-prices[i-1];
            int tmp = sell;
            sell = max(sell+diff, buy+prices[i]);
            if (i>1)    buy = max(buy-diff, pre_sell-prices[i]);
            else        buy = buy-diff;
            pre_sell = tmp;
            result = max(result, max(sell, buy));
        }
        return result;
	}
};

 

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