典型dp,問題的關鍵在于找到一個變量來表示不同的狀態以及推演出狀態轉移方程
這道題目有3種可能的狀態,buy,sell,rest,其中rest表示冷凍期。
借助3個輔助數組buy[i],sell[i],rest[i]:
buy[i]:表示第i天前,任何以buy狀態結尾的交易序列所獲得的最大利潤
sell[i]:表示第i天前,任何以sell狀態結尾的交易序列所獲得的最大利潤
rest[i]:表示第i天前,任何以rest狀態結尾的交易序列所獲得的最大利潤
我們需要得到這3個狀態的轉移方程,通過推算,可以得出以下3條結論:
buy[i] = max(rest[i-1]-price, buy[i-1])
sell[i] = max(buy[i-1]+price, sell[i-1])
rest[i] = max(sell[i-1], buy[i-1], rest[i-1])
解釋:
1.對于buy[i],表示第i天前以buy結尾的交易所獲得的最大收益。
那么第i天有兩種狀態,1.buy(買) 2.rest(觀察)
當第i天選擇購買的時候,此時buy[i] = rest[i-1] -price (購買之前必須經歷冷凍期)
當第i天選擇不買的時候,根據buy[i]的定義, buy[i] = buy[i-1],此時的收益就是第i-1天前以buy結尾的交易所獲得的最大收益
2.sell同理。
細節:1.rest必須出現在buy之前 2.buy必須出現在sell之后
如何確保,排除 buy rest buy 的情況
答案在這里:buy[i] <= rest[i] 推出 rest[i]=max(sell[i-1],rest[i-1])
這避免了buy rest buy 的情況
同時: sell[i] >= rest[i] 推出 rest[i] = sell[i-1]
通過上面3條狀態轉移方程,可能出現的情況為:
1.rest buy (i天買)
buy rest
2.sell rest
buy rest sell(i天賣)
3.buy rest (這條?1.i天買, 會出現 buy rest buy)
sell rest
rest rest
將結論代入 buy[i] 可以將3條狀態轉移方程優化為2條
buy[i] = max{buy[i-1],sell[i-2]-price}
sell[i] = max{sell[i-1],buy[i-1]+price}
但是還可以優化的更好:通過觀察得出第i天的最大收益,只與i-1,i-2天有關。其中sell[i-2] = sell[i-1]。可以將O(n)的空間復雜度轉化為O(1)
public int maxProfit(int[] prices) {
int sell = 0, prev_sell = 0, buy = Integer.MIN_VALUE, prev_buy;
for (int price : prices) {
prev_buy = buy;
buy = Math.max(prev_sell - price, prev_buy);
prev_sell = sell;
sell = Math.max(prev_buy + price, prev_sell);
}
return sell;
}