给定一个数组,它的第 i
个元素是一支给定的股票在第 i
天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入:prices = [3,3,5,0,0,3,1,4] 输出:6 解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。 随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。
示例 2:
输入:prices = [1,2,3,4,5] 输出:4 解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:
输入:prices = [7,6,4,3,1] 输出:0 解释:在这个情况下, 没有交易完成, 所以最大利润为 0。
示例 4:
输入:prices = [1] 输出:0
提示:
1 <= prices.length <= 10^5
0 <= prices[i] <= 10^5
123.买卖股票的最佳时机 III
(1)解题思路
# 分析:当前状态受之前的状态所影响,采用动态规划
# 数组:当前节点共有五种情况——不操作、第一次持有、第一次不持有、第二次持有、第二次不持有
# 递推关系:为好理解层次关系,此处采用二维数组表示
dp[i][0] = dp[i-1][0]
dp[i][1] = max(dp[i-1][1], dp[i-1][0]-prices[i])
dp[i][2] = max(dp[i-1][2], dp[i-1][1]+prices[i])
dp[i][3] = max(dp[i-1][3], dp[i-1][2]-prices[i])
dp[i][4] = max(dp[i-1][4], dp[i-1][3]+prices[i])
# 初始化:为降低时间复杂度,此处采用一维滚顶数组的思想存储过程变量
其中 dp_3 和 dp_4 需理解为当天多次交易的结果
dp_0 = 0
dp_1 = -prices[0]
dp_2 = 0 # 理解为当天买卖过一次之后的结果
dp_3 = -prices[0] # 理解为当天经历过买卖过一次之后,又买入的情况
dp_4 = 0 # 理解为当天买卖过两次之后的结果
# 结果:原本写的是 sum(dp_2, dp_4),但其实 dp_4 中其实是包括了 dp_2 的,因为如果仅买卖过一次后,dp_4 又在当天买卖过一次了
(2)过程想法
从动规五部曲的框架着手写代码是比较好写的,着重理解“数组”——状态种数,“递推”——结合实际情形去写递推关系;
想着有空多回头看看之前写的题目,从框架和实际作用的对比角度去重新审视题目。
class Solution:
def maxProfit(self, prices: List[int]) -> int:
# 分析:当前状态受之前的状态所影响,采用动态规划
# 数组:当前节点共有五种情况——不操作、第一次持有、第一次不持有、第二次持有、第二次不持有
"""
递推关系: dp[i][0] = dp[i-1][0]
dp[i][1] = max(dp[i-1][1], dp[i-1][0]-prices[i])
dp[i][2] = max(dp[i-1][2], dp[i-1][1]+prices[i])
dp[i][3] = max(dp[i-1][3], dp[i-1][2]-prices[i])
dp[i][4] = max(dp[i-1][4], dp[i-1][3]+prices[i])
"""
# 初始化:当前状态都由前一状态推演得出
dp_0 = 0
dp_1 = -prices[0]
dp_2 = 0 # 理解为当天买卖过一次之后的结果
dp_3 = -prices[0] # 理解为当天经历过买卖过一次之后,又买入的情况
dp_4 = 0 # 理解为当天买卖过两次之后的结果
for i in range(1, len(prices)):
dp_1 = max(dp_1, -prices[i])
dp_2 = max(dp_2, dp_1+prices[i])
dp_3 = max(dp_3, dp_2-prices[i])
dp_4 = max(dp_4, dp_3+prices[i])
# 原本写的是 sum(dp_2, dp_4),但其实 dp_4 中其实是包括了 dp_2 的,因为如果仅买卖过一次后,dp_4 又在当天买卖过一次了
return dp_4
给你一个整数数组 prices
和一个整数 k
,其中 prices[i]
是某支给定的股票在第 i
天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k
笔交易。也就是说,你最多可以买 k
次,卖 k
次。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入:k = 2, prices = [2,4,1] 输出:2 解释:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。
示例 2:
输入:k = 2, prices = [3,2,6,5,0,3] 输出:7 解释:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4 。 随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。
提示:
1 <= k <= 100
1 <= prices.length <= 1000
0 <= prices[i] <= 1000
188.买卖股票的最佳时机 IV
(1)解题思路
# 分析:与上一题相比,只是将至多交易的次数由常量 2 变成了变量 k 。只需总结初始化和递推关系的统一形式,再代入即可。
# 初始化:当前状态都由前一状态推演得出奇数下标为 -prices[0],偶数下标为 0
dp = [0] * (2*k+1)
for i in range(1, 2*k+1, 2):
if i % 2 == 1:
dp[i] = -prices[0]
# 递推关系
for j in range(1, 2*k+1):
if j % 2 == 1:
dp[j] = max(dp[j], dp[j-1]-prices[i])
else:
dp[j] = max(dp[j], dp[j-1]+prices[i])
(2)过程想法
从动规五部曲的框架着手写代码是比较好写的,着重理解“数组”——状态种数,“递推”——结合实际情形去写递推关系;
想着有空多回头看看之前写的题目,从框架和实际作用的对比角度去重新审视题目。
class Solution:
def maxProfit(self, k: int, prices: List[int]) -> int:
# 分析:当前状态受之前的状态所影响,采用动态规划
# 数组:当前节点共有 2k 种情况——第一次持有、第一次不持有、第二次持有、第二次不持有...
"""
递推关系:
dp[i][1] = max(dp[i-1][1], dp[i-1][0]-prices[i])
dp[i][2] = max(dp[i-1][2], dp[i-1][1]+prices[i])
dp[i][3] = max(dp[i-1][3], dp[i-1][2]-prices[i])
dp[i][4] = max(dp[i-1][4], dp[i-1][3]+prices[i])
...
"""
# 初始化:当前状态都由前一状态推演得出奇数下标为 -prices[0],偶数下标为 0
dp = [0] * (2*k+1)
for i in range(1, 2*k+1, 2):
if i % 2 == 1:
dp[i] = -prices[0]
for i in range(1, len(prices)):
for j in range(1, 2*k+1):
if j % 2 == 1:
dp[j] = max(dp[j], dp[j-1]-prices[i])
else:
dp[j] = max(dp[j], dp[j-1]+prices[i])
return dp[2*k]