題目
給定一個數組,它的第 i 個元素是一支給定的股票在第 i 天的價格。
設計一個算法來計算你所能獲取的最大利潤。你最多可以完成 兩筆 交易。
注意: 你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。
-
示例1:
輸入: [3,3,5,0,0,3,1,4] 輸出: 6 解釋: 在第 4 天(股票價格 = 0)的時候買入,在第 6 天(股票價格 = 3)的時候賣出,這筆交易所能獲得利潤 = 3-0 = 3 。 隨后,在第 7 天(股票價格 = 1)的時候買入,在第 8 天 (股票價格 = 4)的時候賣出,這筆交易所能獲得利潤 = 4-1 = 3 。
-
示例2:
輸入: [1,2,3,4,5] 輸出: 4 解釋: 在第 1 天(股票價格 = 1)的時候買入,在第 5 天 (股票價格 = 5)的時候賣出, 這筆交易所能獲得利潤 = 5-1 = 4 。 注意你不能在第 1 天和第 2 天接連購買股票,之后再將它們賣出。 因為這樣屬于同時參與了多筆交易,你必須在再次購買前出售掉之前的股票。
-
示例3:
輸入: [7,6,4,3,1] 輸出: 0 解釋: 在這個情況下, 沒有交易完成, 所以最大利潤為 0。
解答
-
思路:
prices => size = n
-
首先,反向遍歷一遍,算出[i:n-1](i的取值位0~n-1)范圍內完成一次交易最多可得多少收益;
dp[i] => 第i天到最后一天的范圍內,完成一次交易最多可以獲得的收益;
maxV => 在反向遍歷過程中,記錄的已遍歷部分的最高價格;
-
狀態轉移方程:
-
接著進行正向遍歷, 計算[0:i]范圍內完成一次交易最多可得多少收益:
minV => 記錄在正向遍歷過程中,已遍歷部分的最低價格;
last => 記錄[0:i-1]范圍內完成一次交易最多可得多少收益;
-
狀態轉移方程:
在正向遍歷過程中,通過查詢第一步的dp表,可以知道兩次交易的收益和,記錄最大值;
-
-
代碼:
def maxProfit(self, prices): """ :type prices: List[int] :rtype int (knowledge) 思路: prices => size = n 1. 首先,反向遍歷一遍,算出[i:n-1](i的取值位0~n-1)范圍內完成一次交易最多可得多少收益 - dp[i] => 第i天到最后一天的范圍內,完成一次交易最多可以獲得的收益 - maxV => 在反向遍歷過程中,記錄的已遍歷部分的最高價格 - 狀態轉移方程: dp[i] = 0 i == n - 1 = max(dp[i + 1], maxV - prices[i]) i < n - 1 2. 接著進行正向遍歷, 計算[0:i]范圍內完成一次交易最多可得多少收益: - minV => 記錄在正向遍歷過程中,已遍歷部分的最低價格 - last => 記錄[0:i-1]范圍內完成一次交易最多可得多少收益 - 狀態轉移方程: cur = 0 i == 0 max(last, prices[i] - min) i > 0 3. 在正向遍歷過程中,通過查詢第一步的dp表,可以知道兩次交易的收益和,記錄最大值 """ if not prices: return 0 length = len(prices) # 反向遍歷初始化(可以只交易一次,第二次不交易,所以dp數組要比length+1,并且最后一個元素值為0,代表不做交易) dp = [0 for i in range(length + 1)] dp[length - 1], maxV = 0, prices[length - 1] # 反向遍歷 for i in range(len(prices) - 1, -1, -1): dp[i] = max(dp[i + 1], maxV - prices[i]) if prices[i] > maxV: maxV = prices[i] # 正向遍歷初始化 last, minV, result = 0, prices[0], 0 for i in range(1, len(prices)): cur = max(last, prices[i] - minV) last, result = cur, max(result, cur + dp[i + 1]) if prices[i] < minV: minV = prices[i] return result
測試驗證
class Solution:
def maxProfit(self, prices):
"""
:type prices: List[int]
:rtype int
(knowledge)
思路:
prices => size = n
1. 首先,反向遍歷一遍,算出[i:n-1](i的取值位0~n-1)范圍內完成一次交易最多可得多少收益
- dp[i] => 第i天到最后一天的范圍內,完成一次交易最多可以獲得的收益
- maxV => 在反向遍歷過程中,記錄的已遍歷部分的最高價格
- 狀態轉移方程:
dp[i] = 0 i == n - 1
= max(dp[i + 1], maxV - prices[i]) i < n - 1
2. 接著進行正向遍歷, 計算[0:i]范圍內完成一次交易最多可得多少收益:
- minV => 記錄在正向遍歷過程中,已遍歷部分的最低價格
- last => 記錄[0:i-1]范圍內完成一次交易最多可得多少收益
- 狀態轉移方程:
cur = 0 i == 0
max(last, prices[i] - min) i > 0
3. 在正向遍歷過程中,通過查詢第一步的dp表,可以知道兩次交易的收益和,記錄最大值
"""
if not prices:
return 0
length = len(prices)
# 反向遍歷初始化(可以只交易一次,第二次不交易,所以dp數組要比length+1,并且最后一個元素值為0,代表不做交易)
dp = [0 for i in range(length + 1)]
dp[length - 1], maxV = 0, prices[length - 1]
# 反向遍歷
for i in range(len(prices) - 1, -1, -1):
dp[i] = max(dp[i + 1], maxV - prices[i])
if prices[i] > maxV:
maxV = prices[i]
# 正向遍歷初始化
last, minV, result = 0, prices[0], 0
for i in range(1, len(prices)):
cur = max(last, prices[i] - minV)
last, result = cur, max(result, cur + dp[i + 1])
if prices[i] < minV:
minV = prices[i]
return result
if __name__ == '__main__':
solution = Solution()
print(solution.maxProfit([3, 3, 5, 0, 0, 3, 1, 4]), "= 6")
print(solution.maxProfit([1, 2, 3, 4, 5]), "= 4")
print(solution.maxProfit([7, 6, 4, 3, 1]), "= 0")