我们可以看到这个相当于要分两段,取前一段和后一段的分别最大值。这样分割点遍历,最后是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;
}
};