我们可以看到这个相当于要分两段,取前一段和后一段的分别最大值。这样分割点遍历,最后是O(n^2)的复杂度。
然后优化后,使用一维的DP。可以降低到O(n)。也就是先从左到右扫一遍求得以i结尾的最大利润的数组,然后从右到左扫一遍求得以i开头的最大利润的数组。然后一加就可以了。
public class Solution { public int maxProfit(int[] prices) { // Start typing your Java solution below // DO NOT write main() function if (prices.length == 0 || prices.length == 1) return 0; int ans = 0; int max = 0; int len = prices.length; int historyProfit[] = new int[len]; int futureProfit[] = new int[len]; int valley = prices[0]; for (int i = 1; i < len; i++) { if (prices[i] >= prices[i-1]) { int val = prices[i] - valley ; if (val > max) max = val; } else { if (prices[i] < valley ) valley = prices[i]; } historyProfit[i] = max; } int peek = prices[len - 1]; ans = max; max = 0; for (int i = len - 2; i >= 1; i--) { if (prices[i+1] >= prices[i]) { int val = peek - prices[i]; if (val > max) max = val; } else { if (prices[i] > peek) peek = prices[i]; } futureProfit[i] = max; int p = futureProfit[i] + historyProfit[i-1]; if (p > ans) { ans = p; } } return ans; } }
我的代码比较乱,看看参考代码多么简洁。同时,该讨论第二楼里还有关于更一般情况的讨论,有空好好看看。
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; } };