news 2026/4/20 6:12:57

代码随想录算法训练营第三十五天 | 121. 买卖股票的最佳时机、122.买卖股票的最佳时机II、123.买卖股票的最佳时机III

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
代码随想录算法训练营第三十五天 | 121. 买卖股票的最佳时机、122.买卖股票的最佳时机II、123.买卖股票的最佳时机III

代码随想录算法训练营第三十五天任务

  • 121. 买卖股票的最佳时机
  • 122.买卖股票的最佳时机II
  • 123.买卖股票的最佳时机III

121. 买卖股票的最佳时机

题目链接:121. 买卖股票的最佳时机
贪心思路:前期尽可能地低价买入,后期尽可能地高价卖出。

classSolution{public:intmaxProfit(vector<int>&prices){intlow=INT_MAX;intprofit=0;for(inti=0;i<prices.size();++i){low=min(low,prices[i]);// 寻找低点profit=max(profit,prices[i]-low);}returnprofit;}};

时间复杂度:O(n)
空间复杂度:O(1)

动态规划:

  1. 确定dp数组的下标及其含义
    dp[i][0]:表示第i天持有股票拥有的最多金额。(持有不代表当天买入,还有可能前几天买入,没买出,一直持有)
    dp[i][1]:表示第i天不持有股票拥有的最多金额。

  2. 确定递推公式
    第i天持有股票,由 “第i天之前持有股票” 和 “第i天买入股票”两种状态推导而来: dp[i][0] = max(dp[i-1][0], - prices[i])
    另外注意:题目要求是一次交易,所以第i天买入股票不能由dp[i-1][1]-prices[i] 而来。
    第i天不持有股票,由 “第i天之前不持有股票” 和 “第i天卖出股票”两种状态推导而来: dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i])

  3. 初始化
    由递推公式可知:第i天由第i-1天推导而来
    dp[0][1]: 表示第0天不持有股票, 所以dp[0][1] = 0
    dp[0][0]: 表示第0天持有股票,所以dp[0][0] = -prices[0]

  4. 确定遍历顺序
    从前往后

  5. 举例推导
    输入:[7,1,5,3,6,4]

idp[i][0]dp[i][1]
0-70
1-10
2-14
3-14
4-15
5-15
classSolution{public:intmaxProfit(vector<int>&prices){vector<vector<int>>dp(prices.size(),vector<int>(2,0));dp[0][0]-=prices[0];// 表示第0天持有股票dp[0][1]=0;// 表示第0天不持有股票for(inti=1;i<prices.size();++i){dp[i][0]=max(dp[i-1][0],-prices[i]);dp[i][1]=max(dp[i-1][1],dp[i-1][0]+prices[i]);}returndp[prices.size()-1][1];}};

时间复杂度:O(n)
空间复杂度:O(n)
还可以用翻滚数组,使空间复杂度为O(1)

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

题目链接:122.买卖股票的最佳时机II
这道题和上一道题的区别就在于可以多次交易。
由上述动规五步曲可知,只一点不同,就是 第i天持有股票,由 “第i天之前持有股票” 和 “第i天买入股票”两种状态推导而来: dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]) 第i天买入股票可由前一天不持有股票金额推导而来。

classSolution{public:intmaxProfit(vector<int>&prices){vector<vector<int>>dp(prices.size(),vector<int>(2,0));dp[0][0]-=prices[0];// 表示第0天持有股票dp[0][1]=0;// 表示第0天不持有股票for(inti=1;i<prices.size();++i){dp[i][0]=max(dp[i-1][0],dp[i-1][1]-prices[i]);// 与 121. 买卖股票的最佳时机不同之处dp[i][1]=max(dp[i-1][1],dp[i-1][0]+prices[i]);}returndp[prices.size()-1][1];}};

时间复杂度:O(n)
空间复杂度:O(n)
还可以用翻滚数组,使空间复杂度为O(1)

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

题目链接:123.买卖股票的最佳时机III
这道题要求 最多可以完成 两笔 交易。这个限制就像背包一样,不超过。
想不出来,看题解了,原来是分状态。
动规5步曲安排!

  1. 确定dp数组的下标及其含义
    每天有5种状态:

    状态含义
    0不操作
    1第一次持有
    2第一次不持有
    3第二次持有
    4第二次不持有

    dp[i][j]表示第 i 天的第 j 种状态下的最大金额。

  2. 确定递推公式
    dp[i][1] : 第 i 天第一次持有股票,由 “第 i 天之前第一次持有股票” 和 “第 i 天买入股票”两种状态推导而来。
    dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])
    dp[i][2]: 第 i 天第一次不持有股票,由 “第 i 天之前第一次不持有股票” 和 “第 i 天卖出股票”两种状态推导而来。
    dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i])
    dp[i][3]: 第 i 天第二次持有股票,由 “第 i 天之前第二次持有股票” 和 “第 i 天买入股票”两种状态推导而来。
    dp[i][3] = max(dp[i-1][3], dp[i-1][2] - prices[i])
    dp[i][4]: 第 i 天第二次不持有股票,由 “第 i 天之前第二次不持有股票” 和 “第 i 天卖出股票”两种状态推导而来。
    dp[i][4] = max(dp[i-1][4], dp[i-1][3] + prices[i])

  3. 初始化
    dp[0][0]: 表示第0天不操作,dp[0][0] = 0.
    dp[0][1]: 表示第0天第一次持有, dp[0][1] = -prices[0]
    dp[0][2]: 表示第0天第一次不持有, dp[0][2] = 0
    dp[0][3]: 表示第0天第二次持有, dp[0][3] = -prices[0]
    dp[0][4]: 表示第0天第二次不持有, dp[0][4] = 0
    dp[i][0] : 表示第 i 天什么都不操作,不是第一次持有/不持有,第二次持有/不持有的任何一个状态,无操作,dp[i][0] = 0. 这列数后续也没用到。

  4. 确定遍历顺序
    从前往后

  5. 举例推导
    prices = [3,3,5,0,0,3,1,4]

    iprices[i]dp[i][0]dp[i][1]dp[i][2]dp[i][3]dp[i][4]
    030-30-30
    130-32-32
    250-32-32
    3000222
    4000222
    5300325
    6100325
    7400426
classSolution{public:intmaxProfit(vector<int>&prices){vector<vector<int>>dp(prices.size(),vector<int>(5,0));// dp[0][0] = 0; // 表示第0天不操作dp[0][1]=-prices[0];// 表示第0天第一次持有// dp[0][2] = 0; // 表示第0天第一次不持有dp[0][3]=-prices[0];// 表示第0天第二次持有// dp[0][4] = 0; // 表示第0天第二次不持有for(inti=1;i<prices.size();++i){dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]);dp[i][2]=max(dp[i-1][2],dp[i-1][1]+prices[i]);dp[i][3]=max(dp[i-1][3],dp[i-1][2]-prices[i]);dp[i][4]=max(dp[i-1][4],dp[i-1][3]+prices[i]);}returndp[prices.size()-1][4];}};

时间复杂度:O(n)
空间复杂度:O(n)
还可以用翻滚数组,使空间复杂度为O(1)

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 11:47:19

ATTO系列荧光染料

ATTO是最为常见的荧光染料之一&#xff0c;其可作为一系列生物分子如蛋白质和核酸的荧光标记和分子探针&#xff0c;其波谱涵盖了从紫外光到近红外光范围&#xff0c;是最全波段的荧光标记。与其他染料相比&#xff0c;其在红色光谱区中拥有优良的光稳定性和亮度。 高荧光量子…

作者头像 李华
网站建设 2026/4/19 10:55:58

BODIPY系列荧光染料

BODIPY系列染料&#xff0c;也常叫吡咯硼&#xff0c;BDP系列&#xff0c;是以硼二吡咯(boron-dipyrromethene)为荧光结构母核的染料。BODIPY系列染料的主要特点是结构非对称性&#xff0c;这种不对称的二咯结构可以让BODIPY衍生出非常多样的结构和非常广泛的光谱范围&#xff…

作者头像 李华
网站建设 2026/4/18 13:12:29

22、Linux系统进程管理、内存使用监测与日志文件查看指南

Linux系统进程管理、内存使用监测与日志文件查看指南 1. 识别运行进程 在Linux系统中,了解系统负载和运行进程对于系统管理和故障排查至关重要。负载平均值能反映系统的整体负载情况。例如,在一个四核CPU的系统中,负载平均值为4.0意味着进程对CPU时间的需求恰好等于计算机…

作者头像 李华
网站建设 2026/4/18 18:09:55

24、深入了解 Linux 文本编辑与脚本编写

深入了解 Linux 文本编辑与脚本编写 1. vi/vim 编辑器简介 vi 是为 Unix 编写的第一个全屏文本编辑器,它体积小巧,能适配老式的基于软盘的紧急引导系统。后来,GNU 项目开发了 vi 编辑器的开源替代品,增加了一些改进,称为 “vi improved”,即 vim。尽管大多数 Linux 发行…

作者头像 李华
网站建设 2026/4/18 18:21:25

29、Linux 用户账户管理全攻略

Linux 用户账户管理全攻略 1. 创建新账户 在大多数情况下,当创建新账户时,很多选项使用默认值即可,此时点击“确定”就能完成基本的账户创建操作。新账户会出现在“用户”标签列表中,后续若有需要,还可以对其进行修改或删除。 1.1 从命令行创建账户 在各种 Linux 发行…

作者头像 李华
网站建设 2026/4/18 12:43:20

AutoGPT在能源管理系统中的预测性维护尝试

AutoGPT在能源管理系统中的预测性维护尝试 在风电场的深夜监控中心&#xff0c;警报突然响起&#xff1a;一台主力风机的振动值连续三天超出正常范围。值班工程师尚未登录SCADA系统查看数据&#xff0c;企业微信已收到一份PDF报告——不仅指出齿轮箱存在共振风险&#xff0c;还…

作者头像 李华