首先貼一個discuss區寫的不錯的解釋(引用一下)
這是是其中O(n^2)的解法:
public int maxProfit(int[] prices) {
if(prices == null || prices.length == 0) return 0;
int length = prices.length;
int[] oneProfit = new int[length];
//minimum value from 0 to i(included)
int minSoFar = prices[0];
for(int i = 1; i < length; i++){
oneProfit[i] = Math.max(oneProfit[i - 1], prices[i] - minSoFar);
minSoFar = Math.min(minSoFar, prices[i]);
}
int[] twoProfit = new int[length];
for(int i = 1; i < length; i++){
int max = twoProfit[i - 1];
for(int j = 0; j < i; j++){
max = Math.max(max, prices[i] - prices[j] + oneProfit[j]);
}
twoProfit[i] = max;
}
return twoProfit[length - 1];
}
其中關於這一段的解釋其實我覺得不夠準確
max = Math.max(max, prices[i] - prices[j] + oneProfit[j])
原作者對於交易兩次的思路是,第i天賣或者不賣,不賣的話價值卻決於上一個max,賣的話,我們就要找從1到i天中一個切分點,分別交易兩次,那麼這裏應該是寫成:
max = Math.max(max, prices[i] - prices[j] + oneProfit[j-1])
因爲第j天你不可以同時買入和賣出,如果代碼改成這樣的話,最後結果我們要和oneProfit比較大小從而返回結果,因爲此時twoProfit代表的意思是恰好交易兩次的情況下,得到的最大值。
但是,原來的代碼是可以得到正確的結果的,我們假設不是測試用例的問題,那麼說明,原有的代碼中twoProfit[i]的意思是前i天中最多交易兩次可以得到的最大利潤,這樣就不存在漏解的情況。
我的基本的理解是,oneProfit[i]的值中,可能是第i天賣出的,也可能不是,那麼我們針對這兩種情況下分別看會怎麼執行:
- 如果第i天沒有賣出,那麼twoProfit得到的值就是交易兩次情況下得到的profit
- 如果賣出了,那麼twoProfit實際得到的值是交易一次情況下的profit
最後一遍遍歷下來,我們得到了前i天情況下,交易一次可以得到的最大值和恰好交易兩次情況下的最大值中的最大值,也就是說twoProfit[i]的值的意義變爲了最多兩次交易情況下前i天可以得到的最大利潤,這其實也就是我們修改代碼之後加上的部分,實際並沒有漏解,但是毫無疑問,這樣寫起來就漂亮多了,而且,後面改進算法成時間O(n),空間O(1)情況下,python直接四行代碼可以解決問題