原題見: https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/java
給定一個股票價格(按日期排序)的列表,在最多能夠買賣兩次的狀況下,如何最大化收益;算法
好比:1, 2, 1, 3, 0, 4;code
最大收益爲6,在第三天買入,第四天賣出,第五天買入,第六天賣出;排序
先用動態規劃的算法;用f(i, j) 表示在第i (from 0) 天到第j天,只買賣一次時的最大收益;那麼,要計算買賣兩次的收益,只須要找到一天k,使得f(0, k) + f(k + 1, n - 1)最大便可;leetcode
f(i, j) 是如下各式中的最大值:it
如下是主要的實現代碼:io
func maxProfit(prices []int) int { prices = compact1(prices) prices = compact2(prices) if len(prices) == 0 { return 0 } n := len(prices) fx := make([][]int, n) for i := range fx { fx[i] = make([]int, n) } for k := 1; k < n; k++ { for i := 0; i+k < n; i++ { j := i + k fx[i][j] = max(0, prices[j]-prices[i]) if k == 1 { continue } fx[i][j] = max(fx[i][j], fx[i+1][j]) fx[i][j] = max(fx[i][j], fx[i][j-1]) } } r := fx[0][n-1] for k := 1; k < n-1; k++ { if fx[0][k]+fx[k][n-1] > r { r = fx[0][k] + fx[k][n-1] } } return r }
由於數據可能會不少,在處理以前,先對數據進行了壓縮,只保留那些會影響收益的數據;好比1, 2, 3, 4,只須要保留1, 4; 4, 3, 2, 1 只須要保留4, 1;class
這個算法的時間複雜度是o(n * n), 空間也須要o(n * n);im
但這個題目還有更精簡更快速也更優美的算法,使人印象深入;具體的討論能夠參考 https://discuss.leetcode.com/topic/32288/2ms-java-dp-solution;數據
使用如下四個值表示當前的狀態:
firstBuy: 第一次買入股票的收益;這個值表示爲價格的負數,因此價格越低,收益越高;
firstSell: 第一次賣出股票的收益;firstSell = max(firstSell, firstBuy + currentPrice); 賣出時的價格(加上)第一次買入時的收益(負值);
secondBuy: 第二次買入股票時的收益;secondBuy = max(secondBuy, firstSell - currentPrice);
secondSell: 第二次賣出時的收益;secondSell = max(secondSell, secondBuy + currentPrice);
代碼實現:
func maxProfit2(prices []int) int { firstBuy, firstSell := math.MinInt32, 0 secondBuy, secondSell := math.MinInt32, 0 for _, price := range prices { if firstBuy < -price { firstBuy = -price } if firstSell < firstBuy+price { firstSell = firstBuy + price } if secondBuy < firstSell-price { secondBuy = firstSell - price } if secondSell < secondBuy+price { secondSell = secondBuy + price } } return secondSell }