leetcode | 123. Best Time to Buy and Sell Stock III
阿新 • • 發佈:2018-12-09
題目
Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete at most two transactions.
Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).
Example 1:
Input: [3,3,5,0,0,3,1,4]
Output: 6
Explanation: Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3.
Example 2:
Input: [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are
engaging multiple transactions at the same time. You must sell before buying again.
Example 3:
Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.
思路與解法
從題目可知,我們可以先計算第一次買賣股票所獲得收益,進行儲存,然後再計算買賣第二次買賣股票的收益(與第一次不衝突)加上第一次買賣股票的收益最終取最大值即可。
方法一:
我們可用dp[i][1]
表示第i天為止進行一次買賣股票的最大收益;dp[i][2]
表示第i天為止進行兩次買賣股票的最大收益。
程式碼實現
func max(a, b, c int) (maxx int) {
maxx = a
if maxx < b {
maxx = b
}
if maxx < c {
maxx =c
}
return
}
func maxProfit(prices []int) int {
days := len(prices)
dp := make([][]int, 0)
for i:=0; i<=days; i++ {
dp = append(dp, make([]int, 3))
}
for i:=1; i<=days; i++ {
// 第i天第一次買賣股票的收益預設為前一天的收益
dp[i][1] = dp[i-1][1]
// 以第j天為分界線,在[1~j-1]天尋找第一天收益 + 區間[j+1~i]第二天收益的最大值
// dp[i][2]儲存第i天為止進行兩次股票買賣的最大值。
for j:=1; j<i; j++ {
if prices[i-1] - prices[j-1] > dp[i][1] {
dp[i][1] = prices[i-1] - prices[j-1]
}
for k:=j+1; k<i; k++ {
if dp[j][1] + prices[i-1] - prices[k-1] > dp[i][2] {
dp[i][2] = dp[j][1] + prices[i-1] - prices[k-1]
}
}
dp[i][2] = max(dp[i][2], dp[i-1][2], dp[i][1])
}
}
return dp[days][2]
}
執行結果
上述程式碼實現效率很低,
方法二:
換一種思路,我們可以首先順序計算,得到第i天為止進行一次股票買賣的最大收益儲存為f[i]
;然後倒序計算maxx - prices[i] + f[i-1]
的最大值(maxx
初始值為prices[days-1]
,maxx
儲存的是股票的最大價值,詳情見下方程式碼),即為兩次股票買賣的最大收益。
程式碼實現
func max(a, b int) int {
if a < b {
return b
}
return a
}
func maxProfit(prices []int) int {
days := len(prices)
if days == 0 {
return 0
}
f := make([]int, days)
minn := prices[0]
maxx := prices[days-1]
sum := 0
// f[0]收益為0,所以無需計算
for i:=1; i<days; i++ {
if prices[i] > prices[i-1] {
f[i] = max(f[i-1], prices[i] - minn)
} else {
f[i] = f[i-1]
}
if prices[i] < minn {
minn = prices[i]
}
}
// 兩次股票買賣的最大收益為max(sum, maxx - prices[i] + f[i-1])
for i:=days-1; i>0; i-- {
maxx = max(maxx, prices[i])
if maxx - prices[i] > 0 {
sum = max(sum, maxx - prices[i] + f[i-1])
}
}
// 注意處理邊界問題
if maxx - prices[0] > 0 {
sum = max(sum, maxx - prices[0])
}
return sum
}