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

99 阅读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):当天结束时持有一支股票。
  2. 冷冻期状态(Cooldown):当天结束时处于冷冻期,即当天卖出了一支股票。
  3. 非持有非冷冻期状态(Not Hold):当天结束时未持有股票,且当天不处于冷冻期。

状态变量:

  • hold[i]:第 i 天结束时,处于持有状态的最大利润。
  • cooldown[i]:第 i 天结束时,处于冷冻期的最大利润。
  • not_hold[i]:第 i 天结束时,处于非持有非冷冻期的最大利润。

状态转移方程

  1. 持有状态

    • 可以是从前一天的持有状态延续(没有买入或卖出)。
    • 可以是当天买入股票(从非持有非冷冻期状态转移而来)。

    hold[i]=max⁡(hold[i−1],not_hold[i−1]−prices[i])hold[i] = \max(hold[i-1], not_hold[i-1] - prices[i])

  2. 冷冻期状态

    • 只能从前一天的持有状态卖出股票进入冷冻期。

    cooldown[i]=hold[i−1]+prices[i]cooldown[i] = hold[i-1] + prices[i]

  3. 非持有非冷冻期状态

    • 可以是从前一天的非持有非冷冻期状态延续。
    • 可以是从前一天的冷冻期状态转移(冷冻期结束)。

    not_hold[i]=max⁡(not_hold[i−1],cooldown[i−1])not_hold[i] = \max(not_hold[i-1], cooldown[i-1])

初始状态

  • 第一天持有股票的利润为负,即 hold[0] = -prices[0]
  • 第一天不可能处于冷冻期状态,cooldown[0] = 0
  • 第一天没有持有股票且非冷冻期状态的利润为零,not_hold[0] = 0

结果计算

最终答案为最后一天处于非持有状态的最大利润,即:

result=max⁡(not_hold[n−1],cooldown[n−1])\text{result} = \max(not_hold[n-1], cooldown[n-1])


代码实现

以下是上述动态规划思路的Python实现:

def solution(prices):
    if not prices:
        return 0

    n = len(prices)
    # 初始化状态
    hold = -prices[0]          # 持有股票的最大利润
    not_hold = 0               # 不持有且非冷冻期的最大利润
    cooldown = 0               # 冷冻期的最大利润

    for i in range(1, n):
        prev_hold = hold
        prev_not_hold = not_hold
        prev_cooldown = cooldown

        # 更新持有状态
        hold = max(prev_hold, prev_not_hold - prices[i])

        # 更新不持有状态
        not_hold = max(prev_not_hold, prev_cooldown)

        # 更新冷冻期状态
        cooldown = prev_hold + prices[i]

    # 最终的最大利润是在不持有状态和冷冻期状态中取最大值
    return max(not_hold, cooldown)


if __name__ == "__main__":
    #  You can add more test cases here
    print(solution([1, 2]) == 1 )
    print(solution([2, 1]) == 0 )
    print(solution([1, 2, 3, 0, 2]) == 3 )
    print(solution([2, 3, 4, 5, 6, 7]) == 5 )
    print(solution([1, 6, 2, 7, 13, 2, 8]) == 12 )

复杂度分析

  • 时间复杂度:O(n),其中 n 是股票价格数组的长度。只需遍历一次数组。
  • 空间复杂度:O(1)。使用常数个变量记录状态。

总结与反思

  1. 算法优点

    • 动态规划设计清晰,将问题分解为多个可管理的子问题。
    • 空间复杂度优化到 O(1),节省了内存使用。
  2. 算法扩展性

    • 该算法可扩展到其他类似问题,如加入交易次数限制或更复杂的冷冻期规则。
  3. 反思

    • 初始设计中曾遗漏冷冻期状态的更新逻辑,导致部分测试样例出错。通过检查状态转移方程并补全测试用例,最终解决问题。