📅  最后修改于: 2023-12-03 15:42:02.808000             🧑  作者: Mango
本题目的目标是给定一个数组,数组中的每个数表示该天股票的价格。你最多可以完成 k 次交易(一次交易指买入一支股票,在某个时刻卖出它),设计一个算法来计算你所能获得的最大利润。注意你不能同时参与多个交易(你必须在再次购买股票前出售掉之前的股票)。
该问题可以用动态规划算法来解决。通过状态的定义,状态的转移方程,以及边界条件的确定,可以设计出一个高效的解法。
设 dp[i][j]
表示在第 i 天结束时,最多进行 j 次交易所能获取的最大利润。状态中的 j 表示你还可以进行 j 次交易,数据中有 k 次机会可以进行交易。
不进行交易
dp[i][j] = dp[i-1][j]
当前状态所能获取的最大利润为前一天的最大利润,状态未变化。
进行交易
dp[i][j] = dp[i-1][j-1] + prices[i] - prices[i-1]
在前一天进行了一次买卖操作并获得利润 dp[i-1][j-1]
的情况下,今天进行一次卖出操作可以获得的最大利润为 prices[i] - prices[i-1]
。
另外,由于我们只需要考虑两天内的买卖情况,所以我们可以把状态转移方程中的 prices[i-1]
替换为 lastBuy
。
即:
for i = 1 to n:
for j = 0 to k:
dp[i][j] = max(dp[i-1][j], dp[i-1][j-1] + prices[i] - lastBuy)
lastBuy = min(lastBuy, prices[i] - dp[i-1][j-1])
当 i = 0 或 j = 0 时,交易次数为 0,即 dp[0][j] = dp[i][0] = 0
。
def maxProfit(k: int, prices: List[int]) -> int:
n = len(prices)
if k >= n // 2:
# 当 k 值大于 n/2 时,相当于无限交易
return sum(max(prices[i+1] - prices[i], 0) for i in range(n-1))
dp = [[0] * (k+1)]
lastBuy = [float('inf')] * (k+1)
for i in range(1, n+1):
dp.append([0] * (k+1))
for j in range(1, k+1):
dp[i][j] = max(dp[i-1][j], dp[i-1][j-1] + prices[i-1] - lastBuy[j-1])
lastBuy[j-1] = min(lastBuy[j-1], prices[i-1] - dp[i-1][j-1])
return dp[n][k]
由于共有 n 天股票价格,需要进行 k 次交易,所以时间复杂度为 $O(nk)$。
状态定义为一个二维数组 dp,所以空间复杂度为 $O(nk)$。
若使用滚动数组,则空间复杂度降为 $O(k)$。