给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [3,3,5,0,0,3,1,4]
输出: 6
思路:
首先,有一点最基本的思路弄清楚:
例子:[3,3,5,0,0,3,1,4]
在本题中,限制了交易次数为两次,但是无论交易几次,最低点和最高点一定会包括在其中
也就是例子中,0块买入,4块卖出。唯一的问题在于,本题限制了交易次数为两次,如果直接0块买进,4块卖出,这样的方案按上面的思路,是损失了中间的一笔交易的利润,但我们获得了另外一次交易的机会。
而如果不损失这中间的一笔交易的利润,我们就要损失一次交易的机会。
想清楚这点就很简单了,只要我们在一次交易机会和最低点与最高点中间的交易利润间做出权衡即可。
如0块买进,4块卖出,中间损失的利润为3-1=2,则只要另外一次交易机会能带给我们的超过2,这个损失就是可以接受的。
因此流程为:
1.找出最低点价格所在位置low与最高点价格所在位置high.
2.计算low与high中间折损的利润,如果中间没有波谷自然是最好的,说明中间交易利润损失为0.
3.在[0,low-1]与[high+1,end]两个区间分别寻找两个区间对应的最大利润。如果区间不存在,像这里,右区间已经在4块右边,已经超出了界限了,说明利润为0。
4.将两个区间的最大利润与中间损失利润的绝对值 做对比,选出一个最大值。
5.将这个最大值与1中所计算的low点买进,high点卖出的利润相加,所得到的结果就是最大利润。
代码:
top函数在start与end间寻找最大利润差区域,并返回最大利润差,并以引用的方式将最大利润差区域的两点写入start与end。
bottom函数与top差不多,但是用于寻找中间损失利润的最大值。
class Solution { public: int maxProfit(vector<int>& prices) { int start=0; int end=prices.size()-1; int val1=top(start,end,prices); int tmpstart=start; int tmpend=end; if(val1==0) return 0; int val2=bottom(start,end,prices); int lnum=0; int rnum=tmpstart-1; int lv=top(lnum,rnum,prices); lnum=tmpend+1; rnum=prices.size()-1; int rv=top(lnum,rnum,prices); int result=val1; if(lv>(-val2)||rv>(-val2)) { result+=(lv>rv)?lv:rv; } else result+=(-val2); return result; } private: int top(int& start,int& end,vector<int>& prices) { if(end<0||start>=prices.size()||(start>=end)) return 0; int pre=start; int next=end; int p1=start; int p2=start; int max=INT_MIN; while(p2<=end) { if(prices[p2]>=prices[p1]) { int tmp=prices[p2]-prices[p1]; if(tmp>max) { max=tmp; pre=p1; next=p2; } } else { p1=p2; } p2++; } if(max<0) max=0; start=pre; end=next; return max; } int bottom(int& start,int& end,vector<int>& prices) { int pre=start; int next=end; int p1=start; int p2=start; int min=INT_MAX; while(p2<=end) { if(prices[p2]<=prices[p1]) { int tmp=prices[p2]-prices[p1]; if(tmp<min) { min=tmp; pre=p1; next=p2; } } else { p1=p2; } p2++; } if(min>0) min=0; start=pre; end=next; return min; } };