Problem:
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 (ie, you must sell the stock before you buy again).
思路:先找到最大的transaction fmax,再找到次大的transaction smax。然后把最大的transaction分割成获利最大的两个子transaction。如果分割的子transaction获利大于fmax+smax,则最大获利为分割的子transaction,否则为fmax+smax。算法的时间复杂度为O(n^2)。
再贴两段大神的C++代码。Solution1的时间复杂度为O(n
)。Solution2更具普适性,能以O(kn)的时间复杂度解决k个transaction的问题。论文 "Maximum-Scoring Segment Sets"专门研究了这个问题。
Solution1:
public class Solution {
public int maxProfit(int[] prices) {
if(prices==null||prices.length==0||prices.length==1)
return 0;
int fmax=0,cost=0,fbegin=0,fend=0,smax=0,overlap=0;
for(int i=1;i<prices.length;i++)
{
if(prices[i]-prices[cost]>fmax)
{
fbegin = cost;
fend = i;
fmax = prices[i] - prices[cost];
}
if(prices[i]<prices[cost])
{
cost = i;
}
}
if(fbegin>1)
{
cost = 0;
for(int i=1;i<fbegin;i++)
{
if(prices[i]-prices[cost]>smax)
smax = prices[i] - prices[cost];
if(prices[i]<prices[cost])
{
cost = i;
}
}
}
if(fend<prices.length-2)
{
cost = fend + 1;
for(int i=fend + 2;i<prices.length;i++)
{
if(prices[i]-prices[cost]>smax)
smax = prices[i] - prices[cost];
if(prices[i]<prices[cost])
{
cost = i;
}
}
}
for(int i=fbegin;i<=fend;i++)
{
for(int j=i+1;j<=fend;j++)
{
if(prices[i]-prices[j]>overlap)
overlap = prices[i] - prices[j];
}
}
return fmax+overlap>fmax+smax?fmax+overlap:fmax+smax;
}
public int maxProfit(int[] prices) {
if(prices==null||prices.length==0||prices.length==1)
return 0;
int fmax=0,cost=0,fbegin=0,fend=0,smax=0,overlap=0;
for(int i=1;i<prices.length;i++)
{
if(prices[i]-prices[cost]>fmax)
{
fbegin = cost;
fend = i;
fmax = prices[i] - prices[cost];
}
if(prices[i]<prices[cost])
{
cost = i;
}
}
if(fbegin>1)
{
cost = 0;
for(int i=1;i<fbegin;i++)
{
if(prices[i]-prices[cost]>smax)
smax = prices[i] - prices[cost];
if(prices[i]<prices[cost])
{
cost = i;
}
}
}
if(fend<prices.length-2)
{
cost = fend + 1;
for(int i=fend + 2;i<prices.length;i++)
{
if(prices[i]-prices[cost]>smax)
smax = prices[i] - prices[cost];
if(prices[i]<prices[cost])
{
cost = i;
}
}
}
for(int i=fbegin;i<=fend;i++)
{
for(int j=i+1;j<=fend;j++)
{
if(prices[i]-prices[j]>overlap)
overlap = prices[i] - prices[j];
}
}
return fmax+overlap>fmax+smax?fmax+overlap:fmax+smax;
}
}
Solution2:
class Solution {
public:
int maxProfit(vector<int> &prices) {
// null check
int len = prices.size();
if (len==0) return 0;
vector<int> historyProfit;
vector<int> futureProfit;
historyProfit.assign(len,0);
futureProfit.assign(len,0);
int valley = prices[0];
int peak = prices[len-1];
int maxProfit = 0;
// forward, calculate max profit until this time
for (int i = 0; i<len; ++i)
{
valley = min(valley,prices[i]);
if(i>0)
{
historyProfit[i]=max(historyProfit[i-1],prices[i]-valley);
}
}
// backward, calculate max profit from now, and the sum with history
for (int i = len-1; i>=0; --i)
{
peak = max(peak, prices[i]);
if (i<len-1)
{
futureProfit[i]=max(futureProfit[i+1],peak-prices[i]);
}
maxProfit = max(maxProfit,historyProfit[i]+futureProfit[i]);
}
return maxProfit;
}
};
public:
int maxProfit(vector<int> &prices) {
// null check
int len = prices.size();
if (len==0) return 0;
vector<int> historyProfit;
vector<int> futureProfit;
historyProfit.assign(len,0);
futureProfit.assign(len,0);
int valley = prices[0];
int peak = prices[len-1];
int maxProfit = 0;
// forward, calculate max profit until this time
for (int i = 0; i<len; ++i)
{
valley = min(valley,prices[i]);
if(i>0)
{
historyProfit[i]=max(historyProfit[i-1],prices[i]-valley);
}
}
// backward, calculate max profit from now, and the sum with history
for (int i = len-1; i>=0; --i)
{
peak = max(peak, prices[i]);
if (i<len-1)
{
futureProfit[i]=max(futureProfit[i+1],peak-prices[i]);
}
maxProfit = max(maxProfit,historyProfit[i]+futureProfit[i]);
}
return maxProfit;
}
};
Solution3:
int maxProfit(vector<int> &prices) {
vector<bool> segs(prices.size());
int maxprofit = 0;
for (int transact = 0; transact < 2; ++transact) {
int i0 = 0, c = 0, cmax = 0;
vector<int> s;
for (int i = 0; i < (int)prices.size()-1; ++i) {
if (i > 0 && segs[i] != segs[i-1]) {
i0 = i; c = 0;
}
c = c + prices[i+1] - prices[i];
if ((!segs[i] && c <= 0) || (segs[i] && c >= 0)) {
i0 = i+1; c = 0;
} else if (cmax < abs(c)) {
cmax = abs(c); s = {i0, i};
}
}
if (cmax == 0) break;
for (int i = s[0]; i <= s[1]; ++i) segs[i] = !segs[i];
maxprofit += cmax;
}
return maxprofit;
}
vector<bool> segs(prices.size());
int maxprofit = 0;
for (int transact = 0; transact < 2; ++transact) {
int i0 = 0, c = 0, cmax = 0;
vector<int> s;
for (int i = 0; i < (int)prices.size()-1; ++i) {
if (i > 0 && segs[i] != segs[i-1]) {
i0 = i; c = 0;
}
c = c + prices[i+1] - prices[i];
if ((!segs[i] && c <= 0) || (segs[i] && c >= 0)) {
i0 = i+1; c = 0;
} else if (cmax < abs(c)) {
cmax = abs(c); s = {i0, i};
}
}
if (cmax == 0) break;
for (int i = s[0]; i <= s[1]; ++i) segs[i] = !segs[i];
maxprofit += cmax;
}
return maxprofit;
}