1. 程式人生 > >leetcode | 123. Best Time to Buy and Sell Stock III

leetcode | 123. Best Time to Buy and Sell Stock III

題目

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]
}

執行結果

上述程式碼實現效率很低, O ( N 3 ) O(N^3)
在這裡插入圖片描述

方法二:

換一種思路,我們可以首先順序計算,得到第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 
}

執行結果

在這裡插入圖片描述