先算出所有的赚钱区间,用一个列表存所有的购入时机,用另一个列表存所有的卖出时机。然后在这两个列表里取出两个买入节点,两个卖出节点,把收益最大化:
public class Solution {
public int maxProfit(int[] prices) {
int in = -1;
int index = -1;
List<Integer> buy = new ArrayList<Integer>();
List<Integer> sell = new ArrayList<Integer>();
for (int i=0; i<prices.length; i++) {
if (in == -1) {
in = prices[i];
index = i;
}
if (i==prices.length-1 || prices[i+1]<prices[i]) {
if (prices[i]-in > 0) {
buy.add(index);
sell.add(i);
}
in = -1;
index = -1;
}
}
return countMax(prices, buy, sell, 0, 0, 2);
}
public int countMax(int[] prices, List<Integer> buy, List<Integer> sell, int start, int index, int max) {
if (index >= max || start >= buy.size())
return 0;
int value = 0;
for (int i=start; i<buy.size(); i++) {
for (int j=start; j<sell.size(); j++)
if (sell.get(j) > buy.get(i)) {
int begin = buy.get(i);
int end = sell.get(j);
int profit = prices[end]-prices[begin];
if (profit > 0) {
value = Math.max(value, profit+countMax(prices, buy, sell, j+1, index+1, max));
}
}
}
return value;
}
}
能通过Judge Small
Run Status: Accepted!
Program Runtime: 496 milli secs
Progress: 22/22 test cases passed.
input output expected
[] 0 0
[1] 0 0
[1,2] 1 1
[2,1] 0 0
[3,3] 0 0
[1,2,4] 3 3
[1,4,2] 3 3
[2,1,4] 3 3
[2,4,1] 2 2
[4,1,2] 1 1
[4,2,1] 0 0
[2,2,5] 3 3
[1,1,0] 0 0
[2,1,2,0,1] 2 2
[3,2,6,5,0,3] 7 7
[6,1,3,2,4,7] 7 7
[2,1,4,5,2,9,7] 11 11
[2,1,2,1,0,0,1] 2 2
[2,1,2,1,0,1,2] 3 3
[3,3,5,0,0,3,1,4] 6 6
[1,2,4,2,5,7,2,4,9,0] 13 13
[1,2,4,2,5,7,2,4,9,0,9] 17 17
在Judge Large时, Run Status: Time Limit Exceeded又超时了... 其实这个算法的时间复杂度理论上是O(N^4),只是做了一些优化,把不影响最终结果的那些节点去掉了。 实际上,这些优化有效的,如果没有这些优化,哪怕时间复杂度改进为O(N^2),在这个题的Judge Large数据规模下,还是会超时。
借助做该系列题第一问的思想,昨用O(N)的时间复杂度能算出只交易一次的最大利润,那么最多只交易两次的最大利润为:
1. 把区间分为两个部分,遍历一遍即可,时间复杂度为O(N)
2. 分别求出子区间的最大利润,时间复杂度为O(N)
所以该算法的最终时间复杂度为O(N^2)
public class Solution {
public int maxProfit(int[] prices) {
int in = -1;
int index = -1;
List<Integer> day = new ArrayList<Integer>();
for (int i=0; i<prices.length; i++) {
if (in == -1) {
in = prices[i];
index = i;
}
if (i==prices.length-1 || prices[i+1]<prices[i]) {
if (prices[i]-in > 0) {
day.add(prices[index]);
day.add(prices[i]);
}
in = -1;
index = -1;
}
}
return maxProfit2((Integer[]) day.toArray(new Integer[0]));
}
public int maxProfit2(Integer[] prices) {
int value = 0;
for (int i=0; i<prices.length; i++)
value = Math.max(value, maxIn(prices, 0, i) + maxIn(prices, i, prices.length));
return value;
}
public int maxIn(Integer[] prices, int b, int e) {
if (e < b+1)
return 0;
int[] lowest = new int[e-b];
int[] highest = new int[e-b];
int min = prices[b];
for (int i=b; i<e; i++) {
min = Math.min(min, prices[i]);
lowest[i-b] = min;
}
int max = prices[e-1];
for (int i=e-1; i>=b; i--) {
max = Math.max(max, prices[i]);
highest[i-b] = max;
}
max = 0;
for (int i=0; i<lowest.length; i++)
max = Math.max(max, highest[i]-lowest[i]);
return max;
}
}
运行结果:
Run Status:
Accepted!
Program Runtime: 632 milli secs
Program Runtime: 632 milli secs
可以pass Large Judge,请注意maxProfit 部分的优化操作,如果没有这部分优化,直接用maxProfit2求值,能pass Judge Small,但在Judge Large下会超时。