309. Best Time to Buy and Sell Stock with Cooldown

題目:

Say you have an array for which the i-th 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:

prices = [1, 2, 3, 0, 2]
maxProfit = 3
transactions = [buy, sell, cooldown, buy, sell]

題目大意:

給定一個數組,第i個元素代表某隻股票在第i天的價格。

設計一個算法計算最大收益。你可以完成多次交易(亦即,多次買入、賣出同一只股票),需要滿足下列限制:

你不可以在同一時間參與多個交易(亦即,在買入股票之前必須賣出)。
在賣出股票之後,你不可以在第二天馬上買入。(亦即,需要一天的冷卻(CD)時間)
測試用例見題目描述。

解題思路:

動態規劃(Dynamic Programming)

時間複雜度:O(n)

本題與Best Time to Buy and Sell Stock II唯一的區別是在賣出股票後需要間隔至少一天才能再次買入。

對一天的狀態有:buy買入,sell賣出,cooldown冷卻。

但是對於這一天是否持股只有兩種狀態:持股狀態(buy),沒有持股狀態(sell,cooldown)。

對於當天持股狀態時,至當天的爲止的最大利潤有兩種可能:1、今天沒有買入,跟昨天持股狀態一樣;2、今天買入,昨天是冷卻期,利潤是前天賣出股票時候得到的利潤減去今天股票的價錢。 二者取最大值。

對於當天未持股狀態,至當天爲止的最大利潤有兩種可能:1、今天沒有賣出,跟昨天未持股狀態一樣;2、昨天持有股票,今天賣出了,利潤是昨天持有股票時候的利潤加上今天股票的價錢。 二者取最大值。

直至最後一天的狀態應該是賣出狀態。最終利潤爲sell[n-1];

狀態轉移方程:

sell[i] = max(sell[i-1], buy[i-1] + price[i]);

buy[i] = max(buy[i-1], sell[i-2] - price[i]);

/*
 另一種思路,首先用3個輔助數組表示buy,sell,rest
 buy[i]表示在第i天之前最後一個操作是買,此時的最大收益, 即第i天爲買。

 sell[i]表示在第i天之前最後一個操作是賣,此時的最大收益。

 rest[i]表示在第i天之前最後一個操作是冷凍期,此時的最大收益。

 我們寫出遞推式爲:

 buy[i]  = max(rest[i-1] - price, buy[i-1])
 sell[i] = max(buy[i-1] + price, sell[i-1])
 rest[i] = max(sell[i-1], buy[i-1], rest[i-1])

 上述遞推式很好的表示了在買之前有冷凍期,買之前要賣掉之前的股票。
 一個小技巧是如何保證[buy, rest, buy]的情況不會出現,這是由於buy[i] <= rest[i], 即rest[i] = max(sell[i-1], rest[i-1]),
 即冷凍期前面只可能是冷凍期或者賣,絕對不會出現買!這保證了[buy, rest, buy]不會出現。

 另外,由於冷凍期的存在,我們可以得出rest[i] = sell[i-1],這樣,我們可以將上面三個遞推式精簡到兩個:

 buy[i]  = max(sell[i-2] - price, buy[i-1])
 sell[i] = max(buy[i-1] + price, sell[i-1])
*/
 public static int maxProfitON(int[] prices)
    {
        int size = prices.length;
        int[] buy = new int[size];
        int[] sell = new int[size];
        if (size < 2)
            return 0;

        buy[0] = -prices[0];
        buy[1] = Math.max(buy[0],-prices[1]);
        sell[0] = 0;
        sell[1] = Math.max(sell[0],buy[0]+prices[1]);

        //buy[i]  = max(rest[i-1]-price, buy[i-1])
        //sell[i] = max(buy[i-1]+price, sell[i-1])
        //根據最初始的狀態轉移方程,先寫出來初始化

        for (int i = 2 ; i < prices.length ; i ++)
        {
            buy[i] = Math.max(buy[i-1],sell[i-2]-prices[i]);
            sell[i] = Math.max(sell[i-1],buy[i-1] + prices[i]);
        }

        return sell[size-1];

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