只能買賣兩次股票的狀況下,如何最大化收益

原題見: 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

  1. 0; 若是第i天的價格高於第j天的價格,則不作交易收益最大;
  2. prices(j) - prices(i); 第j天的價格減去第i天的價格;
  3. f(i + 1, j); 第i天不作交易,第i + 1天到第j天交易的最大收益;
  4. f(i, j - 1); 

如下是主要的實現代碼: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
}
相關文章
相關標籤/搜索