Description
Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete at most two transactions.
Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).
Example 1:
Input: [3,3,5,0,0,3,1,4]
Output: 6
Explanation: Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3.
Example 2:
Input: [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are
engaging multiple transactions at the same time. You must sell before buying again.
Example 3:
Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.
分析一
-
這裡我們先解釋最多可以進行k次交易的算法,然後最多進行兩次我們隻需要把k取成2即可。我們還是使用“局部最優和全局最優解法”。我們維護兩種量,一個是目前到達第i天可以最多進行j次交易,最好的利潤是多少(global[i][j]),另一個是目前到達第i天,最多可進行j次交易,并且最後一次交易在當天賣出的最好的利潤是多少(local[i][j])。下面我們來看遞推式,全局的比較簡單,
global[i][j]=max(local[i][j],global[i-1][j]),
也就是去目前局部最好的,和過往全局最好的中大的那個(因為最後一次交易如果包含目前天一定在局部最好的裡面,否則一定在過往全局最優的裡面)。對于局部變量的維護,遞推式是
local[i][j]=max(global[i-1][j-1]+max(diff,0),local[i-1][j]+diff),
也就是看兩個量,第一個是全局到i-1天進行j-1次交易,然後加上今天的交易,如果今天是賺錢的話(也就是前面隻要j-1次交易,最後一次交易取目前天),第二個量則是取local第i-1天j次交易,然後加上今天的內插補點(這裡因為local[i-1][j]比如包含第i-1天賣出的交易,是以現在變成第i天賣出,并不會增加交易次數,而且這裡無論diff是不是大于0都一定要加上,因為否則就不滿足local[i][j]必須在最後一天賣出的條件了)。
代碼一
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.empty()){
return 0;
}
int n=prices.size();
int g[n][3]={0};
int l[n][3]={0};
for(int i=1;i<n;i++){
int diff=prices[i]-prices[i-1];
for(int j=1;j<=2;j++){
l[i][j]=max(g[i-1][j-1]+max(diff,0),l[i-1][j]+diff);
g[i][j]=max(l[i][j],g[i-1][j]);
}
}
return g[n-1][2];
}
};
分析二
- 按照參考部落格的思路,buy1記錄的是所有天最便宜的報價,sell1記錄的是所有天隻進行1次買賣的最大利益;buy2表示在第一次獲得最大利益後,再買到那次交易後最便宜股價是剩餘的淨利潤,sell2記錄的是兩次完整交易的最大利潤。
代碼二
class Solution {
public:
int maxProfit(vector<int> &prices) {
int buy1=INT_MIN;
int sell1=0;
int buy2=INT_MIN;
int sell2=0;
for(int i=0;i<prices.size();i++){ //每次循環表示進入新的一天
buy1=max(buy1,-prices[i]); //記錄之前所有天最便宜的股價
sell1=max(sell1,buy1+prices[i]); //記錄之前所有天隻進行1次買賣的最大利益
buy2=max(buy2,sell1-prices[i]); //記錄之前天先進行1次交易獲得最大利益後,
//再買到那次交易後最便宜股價時剩餘的淨利潤
sell2=max(sell2,buy2+prices[i]); //記錄之前天進行2次完整交易的最大利潤
}
return sell2;
}
};