📌  相关文章
📜  通过最多买卖k次股票获得最大利润(1)

📅  最后修改于: 2023-12-03 15:42:02.808000             🧑  作者: Mango

通过最多买卖k次股票获得最大利润

简介

本题目的目标是给定一个数组,数组中的每个数表示该天股票的价格。你最多可以完成 k 次交易(一次交易指买入一支股票,在某个时刻卖出它),设计一个算法来计算你所能获得的最大利润。注意你不能同时参与多个交易(你必须在再次购买股票前出售掉之前的股票)。

该问题可以用动态规划算法来解决。通过状态的定义,状态的转移方程,以及边界条件的确定,可以设计出一个高效的解法。

解法
状态定义

dp[i][j] 表示在第 i 天结束时,最多进行 j 次交易所能获取的最大利润。状态中的 j 表示你还可以进行 j 次交易,数据中有 k 次机会可以进行交易。

状态转移方程
  1. 不进行交易 dp[i][j] = dp[i-1][j] 当前状态所能获取的最大利润为前一天的最大利润,状态未变化。

  2. 进行交易 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)$。