最佳买卖股票时机含冷冻期--动态规划

博客围绕含冷冻期的股票交易问题,设计算法计算最大利润。可将“买入”“卖出”分开考虑,用动态规划维护每天结束后的“累积最大收益”。定义三种状态,给出状态转移方程和初始条件,最终得出最大利润的计算方法。

给定一个整数数组prices,其中第 prices[i] 表示第 i 天的股票价格 。

设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票): 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:

输入: prices = [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
示例 2:

输入: prices = [1]
输出: 0

提示:

1 <= prices.length <= 5000
0 <= prices[i] <= 1000

一种常用的方法是将“买入”和“卖出”分开进行考虑:“买入”为负收益,“卖出”为正收益。开始,只有“买入”的权利,只能获得负收益。可以使用动态规划维护在股市中每一天结束后可以获得的“累积最大收益”,并以此进行状态转移。

思路

f[i]f[i]f[i] 表示第i天结束之后的“累积最大收益”(从0开始)。我们最多只能同时买入(持有)一支股票,卖出后有冷冻期的限制,因此有三种不同的状态:

  • 目前持有一支股票,对应的“累积最大收益”记为 f[i][0]f[i][0]f[i][0]
  • 目前不持有任何股票,并且处于冷冻期中,对应的“累积最大收益”记为 f[i][1]f[i][1]f[i][1]
  • 目前不持有任何股票,并且不处于冷冻期中,对应的“累积最大收益”记为 f[i][2]f[i][2]f[i][2]

这里的处于冷冻期指的是在第 i 天结束之后的状态。也就是说:如果第 i 天结束之后处于冷冻期,那么第 i+1 天无法买入股票。

第i 天的状态由第 i-1 天状态转移而来,转移方程为:

f[i]][0]=max(f[i−1][0],f[i−1][2]−price[i])f[i]][0] = max(f[i-1][0], f[i-1][2] - price[i])f[i]][0]=max(f[i1][0],f[i1][2]price[i])

f[i][1]=f[i−1][0]+price[i]f[i][1] = f[i-1][0]+price[i]f[i][1]=f[i1][0]+price[i]

f[i][2]=max(f[i−1][1],f[i−1][2])f[i][2] = max(f[i-1][1], f[i-1][2])f[i][2]=max(f[i1][1],f[i1][2])

如果一共有 n 天,答案为:

max(f[n−1][1],f[n−1][2])max(f[n-1][1], f[n-1][2])max(f[n1][1],f[n1][2])

f[n−1][0]f[n-1][0]f[n1][0] 表示最后还持有股票,显然不符合收益最大。

初始条件为:

f[0][0]=−price[0]f[0][1]=0f[0][2]=0f[0][0]=-price[0] \\ f[0][1]=0 \\f[0][2]=0f[0][0]=price[0]f[0][1]=0f[0][2]=0

class Solution:
    def maxProfit(self, prices: list) -> int:
        if not prices:
            return 0

        f = [[-prices[0], 0, 0]] + [[0] * 3 for i in range(len(prices)-1)]
        for i in range(1, len(prices)):
            f[i][0] = max(f[i-1][0], f[i-1][2]-prices[i])
            f[i][1] = f[i-1][0] + prices[i]
            f[i][2] = max(f[i-1][1], f[i-1][2])

        return max(f[-1][1],f[-1][2])


if __name__ == '__main__':
    s = Solution()
    print(s.maxProfit([1,2,3,0,2]))

参考

https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-cooldown/solution/zui-jia-mai-mai-gu-piao-shi-ji-han-leng-dong-qi-4/

<think>好的,我需要帮助用户理解冷冻股票买卖最佳时机动态规划算法,并给出Python实现。首先,我得回顾一下用户提供的引用资料,特别是引用[5]中的代码和思路。用户的问题是关于动态规划解决这个问题的具体步骤和代码实现。 首先,这个问题的主要约束是卖出股票后有一天冷冻,不能立即买入。动态规划通常适用于这类问题,因为它可以分解问题到每天的状态,并记录每个状态下的最大收益。根据引用[5],状态被分为四种:保持买入状态、保持卖出状态、当天卖出、冷冻。我需要理清每个状态之间的转移关系。 保持买入状态(状态0):可能是前一天已经是买入状态,或者当天买入。而当天买入又可能来自前一天的冷冻或保持卖出状态。这里需要注意,买入时必须是前一天没有卖出操作,即不在冷冻。 保持卖出状态(状态1):可能是前一天已经是卖出状态,或者前一天是冷冻。这表示当天没有进行任何操作,处于可买入但未买入的状态。 当天卖出(状态2):这只能在当天卖出,所以前一天的必须处于买入状态,卖出后进入冷冻冷冻(状态3):只能在前一天卖出后进入,所以当天的状态由前一天的卖出状态转移而来。 接下来,初始化部分,第一天只能买入或者不操作,所以状态0的初始值为-prices[0],其他状态因为没有卖出,收益为0。 然后,遍历每一天的价格,根据状态转移方程更新每个状态的最大收益。最后,取最后一天所有状态的最大值,因为最终可能处于卖出或冷冻状态。 需要检查代码中的转移方程是否正确,比如状态0的转移是否考虑了所有可能的前驱状态。例如,在状态0的更新中,是否允许从冷冻(状态3)或保持卖出(状态1)后买入?是的,因为冷冻之后的下一天可以买入,而保持卖出状态时也可以随时买入,只要没有卖出操作在前一天。 用户可能需要更详细的解释,比如每个状态的定义和转移逻辑,以及为什么这样设计状态。此外,代码中的初始化是否正确,循环中的处理是否覆盖了所有情况。 最后,需要确保给出的Python代码正确无误,并且与引用[5]中的代码一致,同时解释清楚每一步的作用。可能还需要讨论时间复杂度和空间复杂度,以及优化方法,比如状态压缩,减少空间使用。</think>### 买卖股票最佳时机冷冻动态规划解析 #### 问题核心 在股票交易中,卖出后需等待一天冷冻才能再次买入,需通过动态规划合理规划买卖操作以实现最大收益。 --- ### 一、动态规划状态定义 定义四个状态描述每日可能的交易状态: 1. **状态0**:保持买入状态(当日持有股票) 2. **状态1**:保持卖出状态(当日未持有股票,且未处于冷冻) 3. **状态2**:当日卖出股票 4. **状态3**:处于冷冻(仅持续一天) --- ### 二、状态转移方程 1. **状态0**:$dp[i][0] = \max(dp[i-1][0], \max(dp[i-1][1] - p, dp[i-1][3] - p))$ - 延续前一天的买入状态,或从非冷冻(状态1/3)买入 2. **状态1**:$dp[i][1] = \max(dp[i-1][1], dp[i-1][3])$ - 延续前一天的卖出状态,或前一天是冷冻 3. **状态2**:$dp[i][2] = dp[i-1][0] + p$ - 必须在前一天持有股票时卖出 4. **状态3**:$dp[i][3] = dp[i-1][2]$ - 仅在前一天卖出后进入冷冻 --- ### 三、Python代码实现 ```python def maxProfit(prices): n = len(prices) if n == 0: return 0 dp = [[0] * 4 for _ in range(n)] dp[0][0] = -prices[0] # 初始买入状态 for i in range(1, n): # 状态0: 保持买入或当天买入(需从前一天的卖出/冷冻转移) dp[i][0] = max(dp[i-1][0], max(dp[i-1][1] - prices[i], dp[i-1][3] - prices[i])) # 状态1: 保持卖出或从冷冻转移 dp[i][1] = max(dp[i-1][1], dp[i-1][3]) # 状态2: 当天卖出(必须前一天持有) dp[i][2] = dp[i-1][0] + prices[i] # 状态3: 冷冻(前一天卖出) dp[i][3] = dp[i-1][2] return max(dp[-1]) # 最终取所有状态的最大值 ``` --- ### 四、算法分析 1. **时间复杂度**:$O(n)$,遍历一次价格数组 2. **空间复杂度**:$O(n)$,可优化为$O(1)$(用变量代替二维数组)[^5] 3. **关键点**:明确状态转移关系,冷冻仅影响买入操作的时机[^1][^2] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值