问题
假设你有一个数组,其中的第i个元素表示一只股票在第i天的价格。
设计一个算法找出最大的利润值。你最多只能进行两次交易。
注意:
你不能在同一时间进行多次交易(即你必须在再次买入股票之前卖出当前的股票)
初始思路
我们先来考虑只能进行一次交易的情况,即只能买入并卖出一次。可以尝试在第一天就买入股票,然后按顺序计算后面每一天卖出股票后的利润。将该利润和一个保存最大利润的变量比较,如果更大就更新最大利润。很显然,第一天就买入并在利润最大时卖出肯定不会是所有情况的答案,因为股票的价格是会下跌的。那么在什么情况下我们考虑尝试改变买入的时间呢?和第一天买入的价格相比,后面的价格无非就分两种情况:
- 价格更高。这种情况显然是不可能出现优于第一天买入的利润的。因为[从这天之后第一天买入可能的最高利润]=[第一天到该天的利润]+[该天买入可能的最高利润]。所以这种情况下我们需要维持第一天买入的选择。
- 价格一样或更低。[从这天之后第一天买入可能的最高利润]=[该天买入可能的最高利润]- [第一天到该天的亏损]。这种情况下在该天买入就有可能创造最高利润了。
如此一来我们就可以得到一个O(n)的算法:
设置买入价为第一天的价格
从第二天价格遍历存放价格的数组
如果该天卖出利润 > 0
如果利润大于当前最大利润,更新最大利润
如果该天卖出利润 <= 0
设置买入价为该天价格
现在让我们考虑两次交易的情况。因为不能在没卖出股票的情况下再次买入,所以两次买入卖出的区间是不能交叉的。那么我们可以在用上述方法找到一个新的最大利润后,从下一天开始用同样方法再找一次最大利润。将两个利润相加后尝试更新一个总的最大利润。注意处理完后外层的遍历不能中断,还要继续查找直到遍历完毕。伪代码变化如下:
计算利润:
设置买入价为第一天的价格
从第二天价格遍历存放价格的数组
如果该天卖出利润 > 0
如果利润大于当前最大利润,更新最大利润
如果是在外层函数
第二次利润 = 计算利润(当前天数+1作为第一天)
如果利润+第二次利润大于总最大利润,更新总最大利润
如果该天卖出利润 <= 0
设置买入价为该天价格
如果是在外层函数,返回总最大利润
否则返回当前最大利润
转换成C++代码后如下:
1 class Solution { 2 public: 3 int maxProfit(std::vector<int> &prices) 4 { 5 return CaculateProfit(prices, 0, FIRST).profit; 6 } 7 8 private: 9 struct Profit 10 { 11 Profit() : profit(0), buyPrice(-1), buyDay(0), sellDay(0) 12 { 13 } 14 15 int profit; 16 int buyPrice; 17 int buyDay; 18 int sellDay; 19 }; 20 21 enum Transaction 22 { 23 FIRST, 24 SECOND 25 }; 26 27 Profit CaculateProfit(std::vector<int> &prices, int start, Transaction transaction ) 28 { 29 Profit currentProfit; 30 Profit maxProfit; 31 Profit secondProfit; 32 Profit totalProfit; 33 34 for(int day = start; day < prices.size(); ++day) 35 { 36 if(currentProfit.buyPrice == -1) 37 { 38 currentProfit.buyPrice = prices[day]; 39 currentProfit.buyDay = day; 40 continue; 41 } 42 43 currentProfit.profit = prices[day] - currentProfit.buyPrice; 44 currentProfit.sellDay = day; 45 46 if(currentProfit.profit < 0) 47 { 48 currentProfit.buyPrice = prices[day]; 49 currentProfit.buyDay = day; 50 currentProfit.profit = 0; 51 } 52 53 if(currentProfit.profit > maxProfit.profit) 54 { 55 if(transaction == FIRST) 56 { 57 secondProfit = CaculateProfit(prices, day + 1, SECOND); 58 59 60 if(currentProfit.profit + secondProfit.profit > totalProfit.profit) 61 { 62 totalProfit.profit = currentProfit.profit + secondProfit.profit; 63 } 64 } 65 66 maxProfit = currentProfit; 67 } 68 } 69 70 if(transaction == FIRST) 71 { 72 return totalProfit; 73 } 74 else 75 { 76 return maxProfit; 77 } 78 } 79 };
提交后顺利通过Judge Large。