思维导图整理大厂面试高频数组23: 股票问题大总结, 彻底搞懂股票问题

此专栏文章是对力扣上算法题目各种方法总结和归纳, 整理出最重要的思路和知识重点并以思维导图形式呈现, 当然也会加上我对导图的详解.

目的是为了更方便快捷的记忆和回忆算法重点(不用每次都重复看题解), 毕竟算法不是做了一遍就能完全记住的. 所以本文适合已经知道解题思路和方法, 想进一步加强理解和记忆的朋友, 并不适合第一次接触此题的朋友(可以根据题号先去力扣看看官方题解, 然后再看本文内容).

关于本专栏所有题目的目录链接, 刷算法题目的顺序/注意点/技巧, 以及思维导图源文件问题请点击此链接.

想进大厂, 刷算法是必不可少的, 欢迎和博主一起打卡刷力扣算法! 博主同步更新了算法视频讲解, 更易于理解, 不想看文章的 欢迎来看!

关注博主获得题解更新的最新消息!!!

题目链接: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/si-wei-dao-tu-zheng-li-gu-piao-wen-ti-da-9jir/

本文是对所有股票问题的总结归纳, 如果对股票系列问题还不是太了解, 可以先查看下面的相关系列文章, 之后再来看此总结文章. 本文主要是总结股票问题在动态规划解法上的通性, 至于其他的解题方法以及每道题特有的注意点请查看下面的具体文章.

本文也不重复放算法的实现代码了, 因为我都是用java和python两种语言来实现, 之后又对代码进行空间优化, 所以代码中还是有很多的注意点, 直接看具体的文章的讲解效果会更好!

数组17: 股票问题I的通用dp数组定义法 和 贪心法思想, 力扣121

数组18: 股票问题II 和 股票问题I的唯一不同之处, 力扣122

数组19: 股票问题III的dp数组构建/初始化和空间优化难点, 力扣123

数组20: 股票问题IV的dp数组构建和几个重要注意点, 力扣188

数组21: 股票问题+冷冻期的两种dp数组定义方式, 力扣309

数组22: 股票问题+手续费 和股票II的唯一不同之处, 力扣714

0.导图整理

1.股票的通解题目: 最多买卖k次

这道题目是股票问题的通解题目, 也是我认为最困难的题目, 若是按照循序渐进的思想, 可能先讲解 买卖多次 这道题目更容易理解, 但既然是总结归纳了, 还是从全局的角度分析比较好, 更容易将整理系列串联起来.

1.1 状态定义的各种优化问题

首先我们来确定一天会有几个状态, 最容易想到的状态其实是四种:

  • 当天买入了股票
  • 当天卖出了股票
  • 当天没有进行任何操作, 但之前是买入股票的状态
  • 当天没有进行任何操作, 但之前是卖出股票的状态

这是四种大家最容易想到的状态, 但是同时操作四个状态确实有点复杂了, 通过分析后我们可以将这四个状态优化成两个状态: 当天持有股票 和 当天不持有股票, 每个状态又是由两种情况组合而成, 本质上还是四个状态, 只不过通过优化后我们就只需要操作两个状态了.

下面我们考虑如何表示这两个状态, 大家最常见的方法就是使用dp[0]和dp[1]来表示这两种状态了, 这种方式不仅不方便识别dp数组的定义, 而且还增加了dp数组的一个维度, 就本题而言, 如果这样定义的话, 那我们最终就会得到一个三维的dp数组, 操作起来可以说是相当麻烦了.

所以我通常采取的办法就是直接用两个能明确表示dp数组含义的名称来进行命名, 比如用have表示持有股票的状态, 用no表示不持有股票的状态(也有人用buy和sell两个名称, 但我感觉不是太好), 这样定义之后, 不仅含义清晰明了, 还省下了一个维度.

最后的步骤就是确定dp数组有几个维度了. 首先必须有表示天数i的一个维度, 本题还必须有表示买卖k次股票的j这个维度, 所以最终就得到了两个二维的dp数组定义如下图:

这就是整个dp数组定义的过程了, 说的比较多, 因为dp数组的定义对动态规划来说应该是最重要的了!

1.2 确定递推公式

在确定递推公式时, 我们必须先明确一个概念: k何时进行变化. 这点很重要, 直接就导致之后递推公式的不同. 官方题解是默认一买一卖才算完整交易一次, 买入不算交易, 卖出才算一次交易, 所以只有卖出时k变化. 当然也有人定义的是买入时k变化, 这种就会产生不同的递推公式, 但都是正确的.

确定了这个条件之后, 递推公式就没太大难度了, 就是每种状态都由两种情况组合而来, 最终取最大值:

根据上面我们定义的k何时变化, 体现在递推公式中就是在推导no[i][j]的第二种情况时用到的have[i-1][j-1], 因为卖出股票时k会变化, 所以上一个持有股票的状态就是j-1了. 这点一定要注意, 它不止在递推公式中很重要, 也在之后的空间优化时很重要! 这也是推导递推公式的唯一难点了!

1.3 dp数组初始化

本题的初始化过程还是有点复杂的, 但是并不难理解, 这里就不多解释了:

1.4 最终返回结果

由于在所有的 n 天结束后, 手上不持有股票对应的最大利润一定是严格大于手上持有股票对应的最大利润的, 然而完成的交易数并不是越多越好(例如数组prices 单调递减,我们不进行任何交易才是最优的), 因此最终的答案即为no[n−1][0…k]中的最大值.

这就是本道题所有的解题思路了, 一定要好好理解这道通解题目使用的dp数组定义方法, 递推公式推导过程, 下面的几道题在思想上是完全一致的!

当我们将上面的k用具体的数固定住的时候, 就衍生出了下面的几种情况, 这里有一点需要说明: k=1或者+∞对于这个维度来说都是没有意义的, 可以直接忽略掉这个维度, 变成一维数组.

2.k=1时,买卖1次的情况

因为只有一次买卖机会, 所以在买入股票的时候, 之前不会有任何利润, 所以唯一需要更改的地方就是: 第i天买入股票, 所得现金就是买入今天的股票后所得现金即:-prices[i].

3.k=+∞时,买卖多次的情况

本题的由来有两种思想, 可以看成将k固定成+∞的情况, 直接将dp数组的第二个维度去掉即可, 就是最终答案.

也可以看成是由k=1的情况变化而来, 这里唯一不同的地方就是: 因为可以进行多次买卖, 所以在买入股票的时候, 之前可能会有其他利润. 唯一需要更改的地方就是: 第i天买入股票, 所得现金就是昨天不持有股票的所得现金减去 今天的股票价格no[i-1]-prices[i].

4.k=+∞时加冷冻期,买卖多次加冷冻期的情况

这就是在买卖多次的基础上加上了冷冻期的情况, 因为冷冻期是只会在卖出股票后产生的情况, 也就是对应着 不持有股票 的情况, 所以和冷冻期有关的就只有 第i天买入股票 的情况了, 其他的三种状态都和冷冻期关系不大, 并未受太大影响, 递推公式也没什么变化.

下面我们就来着重分析这种情况, 当第i天买入股票时, 那第i-1天必定是不持有股票且不能是冷冻期, 而只用no[i-1]这个状态并不能区别出是否为冷冻期, 所以这里我们采用no[i-2]这个状态.

现在我们来说明这个状态的合理性: no[i-2]由两种情况组成:

  • 如果no[i-2]是在第i-2天卖出股票, 那第i-1天就是冷冻期, 那第i天就解冻了.
  • 如果no[i-2]是延续了前一天i-3天不持有股票的状态, 那么在第i-1天就不会有股票被卖出, 那么第i天也不会是冷冻期.

综合上述两种情况, 无论no[i-2]是由哪个情况转移而来, 第i天都不是冷冻期.

最后讨论一个问题: no[i-2]是否为最大利润

上述说明了使用了no[i-2]的合理性, 那么就剩最后一个问题了, 我们跳过了no[i-1]这个状态, 那么no[i-2]是否就是当前的最大利润呢?

这里还是用上述no[i-2]的两种情况来说明:

  • 如果no[i-2]是在第i-2天卖出股票, 那第i-1天就是冷冻期, 利润不会发生变化.
  • 如果no[i-2]是延续了前一天i-3天不持有股票的状态, 那么在i-1天可能延续i-2天不持有股票的状态, 利润仍然不变, 也可能在i-1天买入股票, 首先利润就变小了, 其次状态也变为have[i-1], 不是我们需要的no状态.

综合两种情况来看, no[i-2]就是当前的最大利润, 这点理解之后, 递推公式就没什么难度了.

5.k=+∞时加手续费,买卖多次加手续费的情况

这就是在买卖多次的基础上加上手续费的情况, 我们默认手续费在卖出时支付, 只需要在卖出股票的同时减去手续费, 递推公式也就只有这一点不同.

如果默认在购买时支付手续费, 那要注意在初始化时have[0]就要减去手续费了, 其他的都没什么区别了.

6.k=2时,最多买卖两次的情况

k=2时, 可以采用二维数组, 但遍历的时候也需要用二重循环来遍历, 比较麻烦.

这时我们能发现当k=2时一共就四个状态, 直接用四个一维数组更清晰明了.

定义了具体的4个状态之后, 递推公式的推导也不是太困难:

至此, 6道股票问题就全部总结完了, 这就是它们在动态规划题解上的通性, 至于其他解题思路(贪心法)以及各种初始化, 空间优化和代码上的细节在相应文章中已经讲解的很清楚, 本文就不过多讲解了.

我的更多精彩文章链接, 欢迎查看

各种电脑/软件/生活/音乐/动漫/电影技巧汇总(你肯定能够找到你需要的使用技巧)

力扣算法刷题 根据思维导图整理笔记快速记忆算法重点内容(欢迎和博主一起打卡刷题哦)

计算机专业知识 思维导图整理

最值得收藏的 Python 全部知识点思维导图整理, 附带常用代码/方法/库/数据结构/常见错误/经典思想(持续更新中)

最值得收藏的 C++ 全部知识点思维导图整理(清华大学郑莉版), 东南大学软件工程初试906科目

最值得收藏的 计算机网络 全部知识点思维导图整理(王道考研), 附带经典5层结构中英对照和框架简介

最值得收藏的 算法分析与设计 全部知识点思维导图整理(北大慕课课程)

最值得收藏的 数据结构 全部知识点思维导图整理(王道考研), 附带经典题型整理

最值得收藏的 人工智能导论 全部知识点思维导图整理(王万良慕课课程)

最值得收藏的 数值分析 全部知识点思维导图整理(东北大学慕课课程)

最值得收藏的 数字图像处理 全部知识点思维导图整理(武汉大学慕课课程)

红黑树 一张导图解决红黑树全部插入和删除问题 包含详细操作原理 情况对比

各种常见排序算法的时间/空间复杂度 是否稳定 算法选取的情况 改进 思维导图整理

人工智能课件 算法分析课件 Python课件 数值分析课件 机器学习课件 图像处理课件

考研相关科目 知识点 思维导图整理

考研经验–东南大学软件学院软件工程(这些基础课和专业课的各种坑和复习技巧你应该知道)

东南大学 软件工程 906 数据结构 C++ 历年真题 思维导图整理

东南大学 软件工程 复试3门科目历年真题 思维导图整理

最值得收藏的 考研高等数学 全部知识点思维导图整理(张宇, 汤家凤), 附做题技巧/易错点/知识点整理

最值得收藏的 考研线性代数 全部知识点思维导图整理(张宇, 汤家凤), 附带惯用思维/做题技巧/易错点整理

高等数学 中值定理 一张思维导图解决中值定理所有题型

考研思修 知识点 做题技巧 同类比较 重要会议 1800易错题 思维导图整理

考研近代史 知识点 做题技巧 同类比较 重要会议 1800易错题 思维导图整理

考研马原 知识点 做题技巧 同类比较 重要会议 1800易错题 思维导图整理

考研数学课程笔记 考研英语课程笔记 考研英语单词词根词缀记忆 考研政治课程笔记

Python相关技术 知识点 思维导图整理

Numpy常见用法全部OneNote笔记 全部笔记思维导图整理

Pandas常见用法全部OneNote笔记 全部笔记思维导图整理

Matplotlib常见用法全部OneNote笔记 全部笔记思维导图整理

PyTorch常见用法全部OneNote笔记 全部笔记思维导图整理

Scikit-Learn常见用法全部OneNote笔记 全部笔记思维导图整理

Java相关技术/ssm框架全部笔记

Spring springmvc Mybatis jsp

科技相关 小米手机

小米 红米 历代手机型号大全 发布时间 发布价格

常见手机品牌的各种系列划分及其特点

历代CPU和GPU的性能情况和常见后缀的含义 思维导图整理

  • 27
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤柒「一起学计算机」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

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

抵扣说明:

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

余额充值