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];
}
};