在 Leetcode 中,关于买卖股票的问题共有6道,而这些题目是可以用相同的思维进行求解的,强烈推荐这篇总结,写得非常到位。

股票类问题的动态规划分三步走,1、首先明确方程的含义

T[i][k][0]:表示在第 i 天结束时,最多进行 k 次交易且在进行操作后持有 0 份股票的情况下可以获得的最大收益;
T[i][k][1]:表示在第 i 天结束时,最多进行 k 次交易且在进行操作后持有 1 份股票的情况下可以获得的最大收益。

2、初始(基准)情况

T[-1][k][0] = 0, T[-1][k][1] = -Infinity
T[i][0][0] = 0, T[i][0][1] = -Infinity

T[-1][k][0] = 0:交易开始前没有股票,收益为0;
T[-1][k][1] = -Infinity:交易开始前有股票,这是不可能的,为负收益;
T[i][0][0] = 0:交易开始了,不允许买股票也不持有股票,收益为0;
T[i][0][1] = -Infinity:交易开始了,不允许买股票但是持有股票,这是不可能的,收益为0。

3、状态转移方程

T[i][k][0] = max(T[i - 1][k][0], T[i - 1][k][1] + prices[i])
T[i][k][1] = max(T[i - 1][k][1], T[i - 1][k - 1][0] - prices[i])

第一行:第 i 天没有股票的最大收益,是上一天也没有股票(挂机)的收益和上一天有股票然后今天卖掉的收益,两者中最大的。
第二行:第 i 天持有股票的最大收益,是上一天也持有股票(挂机)的收益和上一天没有股票然后今天买了股票的收益,两者中最大的。注意允许交易的次数 k 在买入时减去1

121. 买卖股票的最佳时机(剑指 Offer 63. 股票的最大利润)

只能买卖一次股票,k = 1,状态转移方程为:

T[i][1][0] = max(T[i - 1][1][0], T[i - 1][1][1] + prices[i])
T[i][1][1] = max(T[i - 1][1][1], T[i - 1][0][0] - prices[i]) = max(T[i - 1][1][1], -prices[i])
class Solution:def maxProfit(self, prices: List[int]) -> int:n = len(prices)dp = [[0] * 2 for _ in range(n)]dp[0][0] = 0 dp[0][1] = -prices[0]for i in range(1, n):dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i])dp[i][1] = max(dp[i - 1][1], -prices[i])return dp[n - 1][0]

122. 买卖股票的最佳时机 II

可以无限次买卖股票,k 为正无穷,状态转移方程为:

T[i][k][0] = max(T[i - 1][k][0], T[i - 1][k][1] + prices[i])
T[i][k][1] = max(T[i - 1][k][1], T[i - 1][k - 1][0] - prices[i]) = max(T[i - 1][k][1], T[i - 1][k][0] - prices[i])
class Solution:def maxProfit(self, prices: List[int]) -> int:n = len(prices)dp = [[0] * 2 for _ in range(n)]dp[0][0] = 0 dp[0][1] = -prices[0]for i in range(1, n):dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i])dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i])return dp[n - 1][0]

123. 买卖股票的最佳时机 III

最多买卖两次股票,k = 2,状态转移方程为:

T[i][2][0] = max(T[i - 1][2][0], T[i - 1][2][1] + prices[i])
T[i][2][1] = max(T[i - 1][2][1], T[i - 1][1][0] - prices[i])
T[i][1][0] = max(T[i - 1][1][0], T[i - 1][1][1] + prices[i])
T[i][1][1] = max(T[i - 1][1][1], T[i - 1][0][0] - prices[i]) = max(T[i - 1][1][1], -prices[i])
class Solution:def maxProfit(self, prices: List[int]) -> int:n = len(prices)dp = [[[0] * 2 for _ in range(3)] for _ in range(n)]dp[0][1][0] = 0dp[0][1][1] = -prices[0]dp[0][2][0] = 0dp[0][2][1] = -prices[0]for i in range(1, n):dp[i][2][0] = max(dp[i - 1][2][0], dp[i - 1][2][1] + prices[i])dp[i][2][1] = max(dp[i - 1][2][1], dp[i - 1][1][0] - prices[i])dp[i][1][0] = max(dp[i - 1][1][0], dp[i - 1][1][1] + prices[i])dp[i][1][1] = max(dp[i - 1][1][1], dp[i - 1][0][0] - prices[i])return dp[n - 1][2][0]

188. 买卖股票的最佳时机 IV

k 为给定的任意值,买卖要两天时间,天数 n 是有限的,所以实际上的 k 为 min(k, n // 2)。

class Solution:def maxProfit(self, k: int, prices: List[int]) -> int:if not prices:return 0n = len(prices)k = min(k, n // 2)dp = [[[0] * 2 for _ in range(k+1)] for _ in range(n)]for i in range(1, k+1):dp[0][i][0] = 0dp[0][i][1] = -prices[0]for i in range(1, n):for j in range(1, k+1):dp[i][j][0] = max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i])dp[i][j][1] = max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i])return dp[n - 1][k][0]

309. 最佳买卖股票时机含冷冻期

k 实际上为正无穷,但是有冷冻期,如果要在第 i 天买入股票,第二个状态转移方程中就不能使用 T[i - 1][k][0],而应该使用 T[i - 2][k][0],状态转移方程为:

T[i][k][0] = max(T[i - 1][k][0], T[i - 1][k][1] + prices[i])
T[i][k][1] = max(T[i - 1][k][1], T[i - 2][k][0] - prices[i])
class Solution:def maxProfit(self, prices: List[int]) -> int:n = len(prices)dp = [[0] * 2 for _ in range(n)]dp[0][0] = 0dp[0][1] = -prices[0]for i in range(1, n):dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i])dp[i][1] = max(dp[i - 1][1], dp[i - 2][0] - prices[i])return dp[n - 1][0]

714. 买卖股票的最佳时机含手续费

k 实际上为正无穷,但是有手续费,在买入(第一条方程)和卖出(第二条方程)中减去手续费都是可以的,在买入时减去手续费的状态转移方程为:

T[i][k][0] = max(T[i - 1][k][0], T[i - 1][k][1] + prices[i])
T[i][k][1] = max(T[i - 1][k][1], T[i - 1][k][0] - prices[i] - fee)

在卖出时减去手续费的状态转移方程为:

T[i][k][0] = max(T[i - 1][k][0], T[i - 1][k][1] + prices[i] - fee)
T[i][k][1] = max(T[i - 1][k][1], T[i - 1][k][0] - prices[i])
class Solution:def maxProfit(self, prices: List[int], fee: int) -> int:n = len(prices)dp = [[0] * 2 for _ in range(n)]dp[0][0] = 0 dp[0][1] = -prices[0]for i in range(1, n):dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee)dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i])return dp[n - 1][0]

买卖股票类问题动态规划解法(Leetcode题解-Python语言)相关推荐

  1. 爬楼梯与路径类题目记忆化递归与动态规划双解法(Leetcode题解-Python语言)

    70. 爬楼梯(剑指 Offer 10- II. 青蛙跳台阶问题) 递归(英语:Recursion),是指在函数的定义中使用函数自身的方法.有意义的递归通常会把问题分解成规模缩小的同类子问题,当子问题 ...

  2. 岛屿类问题的广度优先深度优先双解法(Leetcode题解-Python语言)

    695. 岛屿的最大面积 先上最经典的题目,详细思路看这题的官方题解,简单来说的岛屿问题就是遍历二维数组,一般都是从一块陆地开始,进行深度优先或者广度优先搜索,每次上下左右四个方向选其一然后寻找下一块 ...

  3. 一般动态规划问题合集(Leetcode题解-Python语言)

    118. 杨辉三角 class Solution:def generate(self, numRows: int) -> List[List[int]]:dp = [[0] * i for i ...

  4. 子串、子数组与子序列类型问题的动态规划求解(Leetcode题解-Python语言)

    一般来说,子串和子数组都是连续的,而子序列是可以不连续的,遇到子序列问题基本上都是用动态规划求解. 53. 最大子数组和(剑指 Offer 42. 连续子数组的最大和) class Solution: ...

  5. 两数、三数、四数之和相关题目(Leetcode题解-Python语言)

    作为 Leetcode 的第一题,两数之和自然是知名度最高的,从两数之和出发也有不少的衍生题目,下面就让我们好好地解决它们. 1. 两数之和 class Solution:def twoSum(sel ...

  6. 链表基础概念与经典题目(Leetcode题解-Python语言)

    所谓链表,就是由链节点元素组成的表,那什么是链节点呢?直接上定义: class ListNode:def __init__(self, val=0, next=None):self.val = val ...

  7. 哈希表(散列表)基础概念与经典题目(Leetcode题解-Python语言)之中——实际应用

    上一节介绍了哈希表的原理与设计方法,这一节则直接python中现有的哈希表类型:哈希集合 set(集合)和哈希映射 dict(字典)来解决实际应用(刷题). 零.概念 在介绍实际应用之前,有一个概念我 ...

  8. 二叉树层序遍历(广度优先搜索)基础概念与经典题目(Leetcode题解-Python语言)

    二叉树的广度优先搜索即从上到下.从左到右地进行搜索,对于层序遍历(Level Order)问题,即依次遍历第一层节点.第二层节点-等,基本可以秒杀. 广度优先搜索是通过队列来实现的,python中优先 ...

  9. 二叉树序列化与反序列化相关题目(Leetcode题解-Python语言)

    297. 二叉树的序列化与反序列化(剑指 Offer 37. 序列化二叉树)(剑指 Offer II 048. 序列化与反序列化二叉树) class Codec:def serialize(self, ...

最新文章

  1. Mondrian xml服务mysql_导入Mondrian例子数据库到mysql中 windows环境
  2. 【转】Cvmat与IplImage的相互转换
  3. UA MATH571A R语言回归分析实践 一元回归4 NBA球员的工资
  4. Spring + JDK Timer Scheduler Example--reference
  5. Hadoop Streaming高级编程
  6. 09--MySQL自学教程:多表查询之内连接、外连接以及【子查询】
  7. Makefile使用及多文件gdb 调试
  8. 安装mlxtend_python机器学习包mlxtend的安装和配置详解
  9. 【Qt开发】QTableWidget设置根据内容调整列宽和行高
  10. 解密 Go interface 的类型转换原理
  11. 如何把图片存入到数据库
  12. linux结构体数组的定义数组,task_struct结构体中的run_list和array域
  13. 春天到了,减肥机器人也到了。
  14. 安装更新Lenovo Solution Center更新失败!具体问题看内容!要是等官方技术人员解决,估计要等上好一段时间!...
  15. 商业智能BI有哪些数据价值
  16. STM32定时器US延时
  17. fatal error C1083,但文件确实却在,也能加载
  18. 性能优化的终极目标-内存简析
  19. mysql连接服务报错1058
  20. 零基础入门学习Python(31)--永久存储:腌制一缸美味的泡菜

热门文章

  1. 【QGIS入门实战精品教程】9.1:QGIS构建泰森多边形(Thiessen Polygon)实例精解
  2. 【数据库原理及应用】经典题库附答案(14章全)——第五章:关系数据理论
  3. 【ArcGIS遇上Python】ArcGIS Python中文编码问题案例详解
  4. Dart语言精简入门介绍
  5. Android之提示Unable to instantiate fragment***MyLikeFragment .could not find Fragment constructor
  6. Android之TypedArray 为什么需要调用recycle()
  7. 【前端就业课 第一阶段】HTML5 零基础到实战(十)JavaScript基础一篇入门
  8. qtabwidget切换tab事件_某超超临界机组初压/限压切换过程中扰动原因分析
  9. 2018年,该转行AI工程师吗?
  10. 51单片机外部地址c语言,cx51与c语言对单片机内部和外部资源变量和地址的定义是否兼容?为什么...