algorithm-base:买卖股票的最佳时机动画教程,动态规划解法

algorithm-base:买卖股票的最佳时机动画教程,动态规划解法

【免费下载链接】algorithm-base 一位酷爱做饭的程序员,立志用动画将算法说的通俗易懂。我的面试网站 www.chengxuchu.com 【免费下载链接】algorithm-base 项目地址: https://gitcode.com/gh_mirrors/al/algorithm-base

你还在为动态规划问题感到头疼吗?面对股票买卖类题目时是否总是无从下手?本文将通过动画模拟的方式,用通俗易懂的语言带你彻底搞懂「买卖股票的最佳时机」问题的动态规划解法,读完你将能够:

  • 理解股票买卖问题的动态规划状态定义
  • 掌握状态转移方程的推导方法
  • 学会优化动态规划的空间复杂度
  • 解决各种变种的股票买卖问题

问题引入

假设你有一个数组,其中第 i 个元素是一支给定股票第 i 天的价格。如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。

注意:你不能在买入股票前卖出股票。

示例:

输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(价格 = 1)的时候买入,在第 5 天(价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

动态规划解题思路

状态定义

我们定义两个状态来描述问题:

  • dp[i][0]:表示第 i 天不持有股票时的最大利润
  • dp[i][1]:表示第 i 天持有股票时的最大利润

状态转移方程

对于 dp[i][0](不持有股票),有两种情况:

  1. 第 i-1 天也不持有股票,今天什么都不做
  2. 第 i-1 天持有股票,今天卖出

所以状态转移方程为:dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])

对于 dp[i][1](持有股票),有两种情况:

  1. 第 i-1 天也持有股票,今天什么都不做
  2. 第 i 天买入股票

所以状态转移方程为:dp[i][1] = max(dp[i-1][1], -prices[i])

初始状态

  • dp[0][0] = 0:第 0 天不持有股票,利润为 0
  • dp[0][1] = -prices[0]:第 0 天持有股票,利润为负的买入价格

空间优化

由于每次计算只需要前一天的状态,我们可以使用两个变量来代替二维数组,将空间复杂度从 O(n) 优化到 O(1):

cash = 0  # 不持有股票的最大利润
hold = -prices[0]  # 持有股票的最大利润

for i in range(1, len(prices)):
    cash = max(cash, hold + prices[i])
    hold = max(hold, -prices[i])
    
return cash

动画模拟过程

下面通过动画来模拟整个计算过程(假设输入 prices = [7,1,5,3,6,4]):

第 0 天

  • 不持有股票:cash = 0
  • 持有股票:hold = -7

第 1 天(价格=1)

  • 不持有股票:max(0, -7+1=-6) → 0
  • 持有股票:max(-7, -1) → -1

第 2 天(价格=5)

  • 不持有股票:max(0, -1+5=4) → 4
  • 持有股票:max(-1, -5) → -1

第 3 天(价格=3)

  • 不持有股票:max(4, -1+3=2) → 4
  • 持有股票:max(-1, -3) → -1

第 4 天(价格=6)

  • 不持有股票:max(4, -1+6=5) → 5
  • 持有股票:max(-1, -6) → -1

第 5 天(价格=4)

  • 不持有股票:max(5, -1+4=3) → 5
  • 持有股票:max(-1, -4) → -1

最终结果为 5,与示例一致。

变种问题拓展

允许无限次交易

如果允许进行无限次交易,状态转移方程只需做一点修改: dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])

完整代码:

cash = 0
hold = -prices[0]

for i in range(1, len(prices)):
    new_cash = max(cash, hold + prices[i])
    new_hold = max(hold, cash - prices[i])
    cash, hold = new_cash, new_hold
    
return cash

最多允许两次交易

对于最多允许两次交易的情况,我们需要定义四个状态:

  • dp[i][0]:未进行任何交易
  • dp[i][1]:进行了一次买入
  • dp[i][2]:进行了一次买入和一次卖出
  • dp[i][3]:进行了两次买入和一次卖出
  • dp[i][4]:进行了两次买入和两次卖出

具体实现可以参考项目中的动态规划章节 【动画模拟】动态规划详解

总结

动态规划是解决股票买卖问题的有效方法,其核心在于:

  1. 定义清晰的状态
  2. 推导出正确的状态转移方程
  3. 合理初始化状态
  4. 必要时进行空间优化

通过本文的学习,你已经掌握了股票买卖问题的动态规划解法。如果想进一步巩固,可以尝试解决以下问题:

希望本文能帮助你更好地理解动态规划思想,在算法学习的道路上更进一步!如果你觉得本文对你有帮助,欢迎点赞、收藏、关注三连,也欢迎在评论区交流讨论。

关于项目

本文内容基于 algorithm-base 项目,这是一个致力于用动画将算法说的通俗易懂的开源项目。项目作者是一位酷爱做饭的程序员,他的面试网站是 www.chengxuchu.com。

项目中还有更多像这样的动画算法教程,涵盖了二分查找、二叉树、动态规划等多个领域,如:

如果你对算法学习感兴趣,不妨去项目中探索更多精彩内容!

【免费下载链接】algorithm-base 一位酷爱做饭的程序员,立志用动画将算法说的通俗易懂。我的面试网站 www.chengxuchu.com 【免费下载链接】algorithm-base 项目地址: https://gitcode.com/gh_mirrors/al/algorithm-base

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值