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.
Example
Given an example [4,4,6,1,1,4,2,5], return 6.
Analysis
一种算法比较容易想到:
找寻一个点j,将原来的prices[0..n-1]分割为prices[0..j]和prices[j..n-1],分别求两段的最大profit。
内层循环与Best Time to Buy and Sell Stock相同,为O(n), 外层循环为O(n),记录不同的j两段maxProfit的值需要O(n)空间,因此总体时间复杂度为O(n^2),空间复杂度为O(n)。
改进(参考pickless的讲解):
对于点j+1,求prices[0..j+1]的最大profit时,很多工作是重复的,在求prices[0..j]的maxProfit中已经计算过了。
类似于Best Time to Buy and Sell Stock,可以在O(1)的时间从prices[0..j]推出prices[0..j+1]的最大profit。
但是如何从prices[j..n-1]推出prices[j+1..n-1]?反过来思考,我们可以用O(1)的时间由prices[j+1..n-1]推出prices[j..n-1]。
最终算法:
数组l[i]记录了prices[0..i]的最大profit,
数组r[i]记录了prices[i..n]的最大profit。
已知l[i],求l[i+1]是简单的,同样已知r[i],求r[i-1]也很容易。
最后,我们再用O(n)的时间找出最大的l[i]+r[i],即为题目所求。
这样时间复杂度O(n), 空间复杂度O(n)
// Assume we are in state S
// If we buy, we are spending money but we can also choose to do nothing
// Doing nothing means going from S->S
// Buying means going from some state X->S, losing some money in the process
S = max(S, X-prices[i])
// Similarly, for selling a stock
S = max(S, X+prices[i])
A Intuitive Implementation Using Divide And Conquer
importjava.util.*;publicclassSolution { /** * @param prices: Given an integer array * @return: Maximum profit */publicintmaxProfit(int[] prices) {// find maxProfit for {0, j}, find maxProfit for {j + 1, n - 1}// find max for {max{0, j}, max{j + 1, n - 1}}if (prices ==null||prices.length==0) {return0; }int maximumProfit =0;int n =prices.length;ArrayList<Profit> preMaxProfit =newArrayList<Profit>(n);ArrayList<Profit> postMaxProfit =newArrayList<Profit>(n);for (int i =0; i < n; i++) {preMaxProfit.add(maxProfitHelper(prices,0, i));postMaxProfit.add(maxProfitHelper(prices, i +1, n -1)); }for (int i =0; i < n; i++) {int profit =preMaxProfit.get(i).maxProfit+postMaxProfit.get(i).maxProfit; maximumProfit =Math.max(profit, maximumProfit); }return maximumProfit; }privateProfitmaxProfitHelper(int[] prices,int startIndex,int endIndex) {int minPrice =Integer.MAX_VALUE;int maxProfit =0;for (int i = startIndex; i <= endIndex; i++) {if (prices[i] < minPrice) { minPrice = prices[i]; }if (prices[i] - minPrice > maxProfit) { maxProfit = prices[i] - minPrice; } }returnnewProfit(maxProfit, minPrice); }publicstaticvoidmain(String[] args) {int[] prices =newint[]{4,4,6,1,1,4,2,5};Solution s =newSolution();System.out.println(s.maxProfit(prices)); }};classProfit {int maxProfit, minPrice;Profit(int maxProfit,int minPrice) {this.maxProfit= maxProfit;this.minPrice= minPrice; }}
Another Implementation with Dynamic Programming
publicclassSolution {publicintmaxProfit(int[] prices) {if (prices ==null||prices.length<=1) {return0; }int[] left =newint[prices.length];int[] right =newint[prices.length];// DP from left to right; left[0] =0;int min = prices[0];for (int i =1; i <prices.length; i++) { min =Math.min(prices[i], min); left[i] =Math.max(left[i -1], prices[i] - min); }//DP from right to left; right[prices.length-1] =0;int max = prices[prices.length-1];for (int i =prices.length-2; i >=0; i--) { max =Math.max(prices[i], max); right[i] =Math.max(right[i +1], max - prices[i]); }int profit =0;for (int i =0; i <prices.length; i++){ profit =Math.max(left[i] + right[i], profit); }return profit; }}