问题:
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).
解决:
【题意】用一个数组表示股票每天的价格,数组的第i个数表示股票在第i天的价格。最多交易两次,手上最多只能持有一支股票,求最大收益。
例子:
Prices: 1 4 5 7 6 3 2 9 left = [0, 3, 4, 6, 6, 6, 6, 8] right= [8, 7, 7, 7, 7, 7, 7, 0]
The maximum profit = 13
最简单的方法就是对每一个时间点,将其所有两边的数组都执行一次Best Time to Buy and Sell Stock I的解法,但这会带来O(N^2)的时间复杂度。会超时。
① 双向动态规划。当计算prices[0]到prices[i]的最大收益时,我们已经计算过prices[0]到prices[i-1]的最大收益了,prices[0]到prices[i]的最大收益应该是当前卖出能获得的最大收益和prices[0]到prices[i-1]的最大收益中,二者较大的那个。我们可以利用这个之前计算的结果降低时间复杂度(不过代价是额外空间),所以需要把prices[0]到prices[i]的最大收益存在left[i]数组中。具体解法和I是一样的,也是维护一个前半段最小值。
分别得出以i点为分割点,左半段最大收益的数组left,和右半段最大收益的数组right后,我们就可以遍历一遍这两个数组,找出最大的left+right组合。实际上,该解法就是将I的解法双向各执行一遍并记录结果。
class Solution { //3ms
public int maxProfit(int[] prices) {
if (prices == null || prices.length == 0) return 0;
int len = prices.length;
int[] left = new int[len];
int[] right = new int[len];
int leftmin = prices[0];
int rightmax = prices[len - 1];
for (int i = 1;i < prices.length;i ++){//左半段最大收益
leftmin = Math.min(leftmin,prices[i]);
left[i] = Math.max(prices[i] - leftmin,left[i - 1]);
}
for (int i = prices.length - 2;i >= 0;i --){//右半段最大收益
rightmax = Math.max(rightmax,prices[i]);
right[i] = Math.max(rightmax - prices[i],right[i + 1]);
}
int max = 0;
for (int i = 0;i < prices.length;i ++){
if (left[i] + right[i] > max){
max = left[i] + right[i];
}
}
return max;
}
}
② discuss中看到的进化版,只使用一个数组即可。
class Solution { //2ms
public int maxProfit(int[] prices) {
if (prices.length < 2) return 0;
int[] profit = new int[prices.length];
for (int k = 0;k < 2;k ++){
int maxBuy = profit[0] - prices[0];//左侧最大利益
for (int i = 1;i < prices.length;i ++){
int tmp = profit[i];
profit[i] = Math.max(profit[i - 1],prices[i] + maxBuy);
maxBuy = Math.max(maxBuy,tmp - prices[i]);
}
}
return profit[prices.length - 1];
}
}