LintCode 151 買賣股票的最佳時機 III
今天做了兩道動態規劃的題目,感覺對動態規劃有了更深入的瞭解。廢話不多說,這是第一道。題目要求如下:
假設你有一個數組,它的第i個元素是一支給定的股票在第i天的價格。設計一個算法來找到最大的利潤。你最多可以完成兩筆交易。
注意事項:
你不可以同時參與多筆交易(你必須在再次購買前出售掉之前的股票)
給出樣例如下:
給出一個樣例數組 [4,4,6,1,1,4,2,5],返回 6
題目給出的框架如下:
class Solution {
public:
/**
* @param prices: Given an integer array
* @return: Maximum profit
*/
int maxProfit(vector<int> &prices) {
// write your code here
}
};
解題思路
一開始的想法是用兩個數組buy[]和sell[]來解決,狀態轉移方程爲:
buy[i] = max(buy[i-1],sell[i-1] - prices[i])
sell[i] = max(sell[i-1],buy[i-1] + prices[i])
最後返回sell[len-1],其中 i 爲當前天數,len爲總共的天數。
想法很簡單,將當前狀態分爲已經買入股票和已經賣出股票這兩種:
1. 如果第 i 天的狀態爲買入股票的話, 要麼就是之前買了股票,第i天不買,對應於buy[i-1];要麼就是之前賣了股票,第i天買入股票,對應於sell[i-1] - prices[i])。
2. 同理, 如果第 i天的狀態爲賣出股票的話,要麼就是之前賣了股票,第i天不賣,對應於sell[i-1];要麼就是之前買了股票,第i天賣掉,對應於buy[i-1]+ prices[i]。
但這忽視了一個條件:
你最多可以完成兩筆交易!
因此,上面的狀態轉移方程解決的問題應該是 :
不管你交易多少筆,你的最大獲利是多少!
這是因爲你沒有限制交易多少筆,所以只要能獲利,我就可以將交易增加到3次,4次甚至更多次,sell[len]的值也會相應的增加。
那如何限制交易的次數爲2呢?
既然你說只能交易兩次,那麼我就對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])
方程很好理解:
1. 如果第 i 天爲第一次買的狀態,要麼就是之前買過了,第i天不賣,對應於firstBuy[i -1],要麼就是之前沒有買,第i天買入股票,對應於-prices[i];
2. 如果第 i 天爲第一次賣的狀態,要麼就是之前賣出了,第i天不買,對應於firstSell[i -1],要麼就是之前買入了股票,第i天賣出股票,對應於firstBuy[i - 1] + prices[i];
3. 如果第 i 天爲第二次買的狀態,要麼就是之前已經二次買過了,第i天不賣,對應於secondBuy[i -1],要麼就是之前賣過一次了,第i天再次買入股票,對應於firstSell[i - 1] - prices[i];
4. 如果第 i 天爲第二次賣的狀態,要麼就是之前已經二次賣過了,第i天不買,對應於secondSell[i -1],要麼就是之前第二次購買,第i天賣出股票,對應於secondBuy[i - 1] + prices[i];
最後,還需要對第一天的買賣進行初始化:
firstBuy[0] = -prices[0]
secondBuy[0] = -prices[0]
firstSell[0] = 0
secondSell[0] = 0
代碼實現
代碼實現如下:
class Solution {
public:
/**
* @param prices: Given an integer array
* @return: Maximum profit
*/
int maxProfit(vector<int> &prices) {
// write your code here
const int len = prices.size();
if (len == 0)
return 0;
int firstBuy[len];
int secondBuy[len];
int firstSell[len];
int secondSell[len];
firstBuy[0] = -prices[0];
secondBuy[0] = -prices[0];
firstSell[0] = 0;
secondSell[0] = 0;
for (int i = 1; i < len; ++i) {
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]);
}
return secondSell[len - 1];
}
};