LintCode 152 買賣股票的最佳時機 IV

LintCode 152 買賣股票的最佳時機 IV

題目要求:

假設你有一個數組,它的第i個元素是一支給定的股票在第i天的價格。設計一個算法來找到最大的利潤。你最多可以完成 k 筆交易。
注意事項:
你不可以同時參與多筆交易(你必須在再次購買前出售掉之前的股票)

給出樣例如下:

給定價格 = [4,4,6,1,1,4,2,5], 且 k = 2, 返回 6.

題目給出的框架如下:

class Solution {
public:
    /**
     * @param k: An integer
     * @param prices: Given an integer array
     * @return: Maximum profit
     */
    int maxProfit(int k, vector<int> &prices) {
        // write your code here
    }
};

解題思路

這道題和上一道題LintCode 151 買賣股票的最佳時機 III 很相似,建議先從上一道題入手。區別在於:上一道題只要求兩次交易,而這道題沒有指定交易次數
對於上一道題,我們的處理方法是用兩個buy和sell矩陣分別記錄第一次和第二次買賣的狀態。但是這道題的交易次數是k,我們不可能去建k個矩陣來存儲k次的buy和sell,那會消耗大量的空間。
所以問題就變成了:如何只建有限個矩陣來存儲呢?
我們先觀察上一道題的狀態轉移方程:

firstBuy[i] = max(firstBuy[i - 1], -prices[i])

firstSell[i] = max(firstSell[i - 1], firstBuy[i - 1] + prices[i])

secondBuy[i] = max( secondBuy[i - 1], firstSell[i - 1] - prices[i])

secondSell[i] = max( secondSell[i - 1], secondBuy[i - 1] + prices[i])

發現什麼問題了沒有?

第 i 天的結果只與第 i - 1 天的結果有關,與 i - 1 之前的天數完全無關!

既然如此,更新只需要用到前一天的數據,那麼我只用兩個矩陣buy[k]sell[k]來存儲當天的k次交易不就行了?!
設第i-1天爲第j次買的狀態時收入爲buy[j],第j次賣的狀態時收入爲sell[j],那麼第i天第j次買的狀態仍然爲buy[j],它的更新有兩種情況:

一種是前一天已經第j次購買,對應於前一天的buy[j]
一種是前一天已經第j-1次賣出,第i天買入,對應於前一天的sell[j-1]減去當天的價格prices[i]

那麼很容易得到當天狀態爲購買的話收入爲:

buy[j] = max(buy[j], sell[j - 1] - prices[i])

同理可得:第i天第j次賣出的狀態sell[j]也有兩種情況:

一種是前一天已經第j次賣出,第j天不買,對應於前一天的sell[j]
一種是前一天已經第j次買入,第j天賣出,對應於前一天的buy[j]加上當天的價格prices[i]

得到當天狀態爲賣出的話收入爲:

sell[j] = max(sell[j], buy[j] + prices[i])

但這是不是就結束了呢?

注意注意,前方高能!

我們看到第 i 天的buy[j]需要用到前一天的sell[j-1],但是如果我們從j=0開始遍歷的話,此時得到的sell[j-1]已經變成了第 i 天的sell[j-1]了啊。

解決方法

從j=k-1開始遍歷到1,那麼修改buy[j]sell[j]之時,就能保證sell[j-1]還是前一天的值

最後就是一些初始化的工作了,特別需要注意buy[0]和sell[0]的更新:

buy[0] = max(buy[0], -prices[i])

sell[0] = max(sell[0], buy[0] + prices[i])


代碼實現

代碼實現如下:

class Solution {
public:
    /**
     * @param k: An integer
     * @param prices: Given an integer array
     * @return: Maximum profit
     */
    int maxProfit(int k, vector<int> &prices) {
        // write your code here
        const int len = prices.size();
        if (len == 0)
            return 0;
        if (k > len / 2)
            k = len / 2;
        const int count = k;
        int buy[count];
        int sell[count];
        for (int i = 0; i < count; ++i) {
            buy[i] = -prices[0];
            sell[i] = 0;
        }
        for (int i = 1; i < len; ++i) {
            buy[0] = max(buy[0], -prices[i]);
            sell[0] = max(sell[0], buy[0] + prices[i]);
            for (int j = count - 1; j > 0; --j) {
                buy[j] = max(buy[j], sell[j - 1] - prices[i]);
                sell[j] = max(buy[j] + prices[i], sell[j]);
            }
        }
        return sell[count - 1];
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章