股票交易市场策略优化 | 豆包MarsCode AI刷题

53 阅读4分钟

问题描述

小R近期表现出色,公司决定以股票的形式给予奖励,并允许他在市场上进行交易以最大化收益。给定一个数组,数组中的第 i 个元素代表第 i 天的股票价格。小R需要设计一个算法来实现最大利润。

股票交易规则如下:

  • 小R可以多次买卖股票,但在买入新的股票前必须卖出之前的股票。
  • 每次卖出股票后存在一天的冷冻期,在冷冻期内小R不能购买股票。

你的任务是帮助小R计算出在遵守交易规则的情况下能够获得的最大利润。

  • stocks: 一个整数列表,表示连续几天内的股票价格。

测试样例

样例1:

输入:stocks = [1, 2]
输出:1

样例2:

输入:stocks = [2, 1]
输出:0

样例3:

输入:stocks = [1, 2, 3, 0, 2]
输出:3

样例4:

输入:stocks = [2, 3, 4, 5, 6, 7]
输出:5

样例5:

输入:stocks = [1, 6, 2, 7, 13, 2, 8]
输出:12

解题思路

动态规划建模

使用动态规划解决该问题,我们将交易过程分为以下三种状态:

  1. 持有股票状态(hold) :在第 i 天结束时,手中仍然持有一只股票。

  2. 未持有股票且非冷冻期状态(rest) :在第 i 天结束时,没有持有股票,也不处于冷冻期。

  3. 冷冻期状态(cooldown) :在第 i 天结束时,没有持有股票,并且当天处于冷冻期。

状态定义

设:

• dp[i][0] 表示第 i 天结束时处于 hold 状态的最大利润。

• dp[i][1] 表示第 i 天结束时处于 rest 状态的最大利润。

• dp[i][2] 表示第 i 天结束时处于 cooldown 状态的最大利润。

状态转移方程

  1. 如果第 i 天结束时处于 hold 状态:

• 前一天也处于 hold 状态。

• 第 i 天买入股票(前一天必须是 rest 状态)。

dp[i][0] = \max(dp[i-1][0], dp[i-1][1] - stocks[i])

  1. 如果第 i 天结束时处于 rest 状态:

• 前一天也处于 rest 状态。

• 前一天处于 cooldown 状态。

dp[i][1] = \max(dp[i-1][1], dp[i-1][2])

  1. 如果第 i 天结束时处于 cooldown 状态:

• 第 i 天卖出了股票(前一天必须是 hold 状态)。

dp[i][2] = dp[i-1][0] + stocks[i]

初始化

• dp[0][0] = -stocks[0]:第 0 天持有股票的最大利润为负数(即买入股票)。

• dp[0][1] = 0:第 0 天没有持有股票且非冷冻期的利润为 0。

• dp[0][2] = 0:第 0 天没有持有股票且处于冷冻期的利润为 0。

最终结果

最后一天的最大利润是:

\max(dp[n-1][1], dp[n-1][2])

因为最终状态必须是 rest 或 cooldown 状态。

def max_profit(stocks):
    n = len(stocks)
    if n <= 1:
        return 0

    # 初始化 dp 数组
    dp = [[0] * 3 for _ in range(n)]
    dp[0][0] = -stocks[0]  # 第一天持有股票的状态
    dp[0][1] = 0           # 第一天非冷冻期的状态
    dp[0][2] = 0           # 第一天冷冻期的状态

    for i in range(1, n):
        # 持有股票状态
        dp[i][0] = max(dp[i-1][0], dp[i-1][1] - stocks[i])
        # 非冷冻期状态
        dp[i][1] = max(dp[i-1][1], dp[i-1][2])
        # 冷冻期状态
        dp[i][2] = dp[i-1][0] + stocks[i]

    # 最终结果
    return max(dp[n-1][1], dp[n-1][2])

# 测试样例
print(max_profit([1, 2]))            # 输出:1
print(max_profit([2, 1]))            # 输出:0
print(max_profit([1, 2, 3, 0, 2]))   # 输出:3
print(max_profit([2, 3, 4, 5, 6, 7]))# 输出:5
print(max_profit([1, 6, 2, 7, 13, 2, 8])) # 输出:12

四、测试讲解

样例 1

输入:stocks = [1, 2]

• 第 0 天买入,第 1 天卖出。

• 利润为  2 - 1 = 1 。

输出:1

样例 2

输入:stocks = [2, 1]

• 不进行任何交易。

• 利润为 0。

输出:0

样例 3

输入:stocks = [1, 2, 3, 0, 2]

• 第 0 天买入,第 2 天卖出,利润为  3 - 1 = 2 。

• 第 3 天冷冻期,第 4 天买入并卖出,利润为  2 。

总利润为  2 + 1 = 3 。

输出:3

样例 5

输入:stocks = [1, 6, 2, 7, 13, 2, 8]

• 第 0 天买入,第 1 天卖出,利润为  6 - 1 = 5 。

• 第 2 天冷冻期,第 3 天买入,第 4 天卖出,利润为  13 - 2 = 11 。

总利润为  5 + 7 = 12 。

输出:12

五、优化方向

1. 空间优化

由于每一天的状态只与前一天相关,可以使用滚动数组将空间复杂度优化为  O(1) 。

优化代码示例:

def max_profit_optimized(stocks):
    n = len(stocks)
    if n <= 1:
        return 0

    hold, rest, cooldown = -stocks[0], 0, 0

    for i in range(1, n):
        prev_hold, prev_rest, prev_cooldown = hold, rest, cooldown
        hold = max(prev_hold, prev_rest - stocks[i])
        rest = max(prev_rest, prev_cooldown)
        cooldown = prev_hold + stocks[i]

    return max(rest, cooldown)