【Day 27】121.买卖股票的最佳时机 122.买卖股票的最佳时机II
文章目录121.买卖股票的最佳时机题目思路举例代码实现Go122.买卖股票的最佳时机II题目思路举例代码实现Go进阶思路动态规划代码实现Go空间优化滚动数组O (1) 空间代码实现Go121.买卖股票的最佳时机题目给定一个数组 prices 它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。你只能选择某一天买入这只股票并选择在未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润返回 0 。示例 1输入[7,1,5,3,6,4]输出5解释在第 2 天股票价格 1的时候买入在第 5 天股票价格 6的时候卖出最大利润 6-1 5 。注意利润不能是 7-1 6, 因为卖出价格需要大于买入价格同时你不能在买入前卖出股票。示例 2输入prices [7,6,4,3,1]输出0解释在这种情况下, 没有交易完成, 所以最大利润为 0。提示1 prices.length 10^50 prices[i] 10^4思路想要一次交易的利润最大本质就是在「遍历到当前天为止的最低点」买入在该最低点之后的任意一天卖出取卖出的最大利润遍历过程中只需维护两个关键变量不用额外空间边遍历边更新每个价格只看一次minPrice遍历到当前天时之前所有天的股票最低价格也就是到目前为止最划算的买入价maxProfit遍历到当前天时能获取的最大利润初始为0无利润时直接返回这个值。遍历的核心两步对每个价格都执行先更新最小买入价如果当前价格比minPrice更低就把minPrice换成当前价格找到更划算的买入点再计算当前利润更新最大利润用当前价格 -minPrice得到「当天卖出的利润」如果这个利润比maxProfit大就更新maxProfit关键如果当前价格等于minPrice第一步不会更新等于不是更低第二步计算的利润为0不会超过maxProfit初始0后续只增不减所以无需单独处理等于的情况自然跳过即可。举例初始化minPrice 数组第一个元素题目保证数组非空无越界风险maxProfit 0无利润时直接返回利润为负也取0。场景1正常上涨有盈利输入价格数组[7,1,5,3,6,4]共6天步骤初始化minPrice7maxProfit0第2天价格11 7 →minPrice1利润1-10 → 不大于0maxProfit0第3天价格55 不小于1 →minPrice不变利润5-14 → 大于0 →maxProfit4第4天价格33 不小于1 →minPrice不变利润3-12 → 小于4maxProfit不变第5天价格66 不小于1 →minPrice不变利润6-15 → 大于4 →maxProfit5第6天价格44 不小于1 →minPrice不变利润4-13 → 小于5maxProfit不变。结果maxProfit5即第2天买入、第5天卖出利润最大。场景2持续下跌无盈利输入价格数组[7,6,4,3,1]共5天步骤初始化minPrice7maxProfit0第2天价格66 7 →minPrice6利润6-60 → 不大于0maxProfit0第3天价格44 6 →minPrice4利润4-40 → 不大于0maxProfit0第4天价格33 4 →minPrice3利润3-30 → 不大于0maxProfit0第5天价格11 3 →minPrice1利润1-10 → 不大于0maxProfit0。结果maxProfit0全程股价下跌无盈利可能直接返回0。场景3含等于价格输入价格数组[7,1,1,5,3,6]共6天第2、3天价格均为1含等于步骤初始化minPrice7maxProfit0第2天价格11 7 →minPrice1利润1-10 → 不大于0maxProfit0第3天价格11 不小于1 →minPrice不变利润1-10 → 不大于0maxProfit不变第4天价格55 不小于1 →minPrice不变利润5-14 → 大于0 →maxProfit4第5天价格33 不小于1 →minPrice不变利润3-12 → 小于4maxProfit不变第6天价格66 不小于1 →minPrice不变利润6-15 → 大于4 →maxProfit5。结果maxProfit5和去掉等于价格的数组[7,1,5,3,6]结果一致等于价格无任何影响只需要比较小于即可。代码实现GopackagemainimportfmtfuncmaxProfit(prices[]int)int{minPrice:prices[0]// 初始化为首个元素maxProfit:0// 无利润返回0利润为负也保持0// 从第二个元素开始遍历索引1首个元素已作为初始minPricefori:1;ilen(prices);i{curPrice:prices[i]// 第一步更新到目前为止的最小买入价仅当前价格更小时更新ifcurPriceminPrice{minPricecurPrice}// 第二步计算当天卖出的利润更新最大利润curProfit:curPrice-minPriceifcurProfitmaxProfit{maxProfitcurProfit}}returnmaxProfit}funcmain(){// 直接构造题目给的输入数组 [7,1,5,3,6,4]prices:[]int{7,1,5,3,6,4}res:maxProfit(prices)fmt.Println(res)}// 或funcmain(){varnintfmt.Scan(n)// 读取价格数组的长度prices:make([]int,n)fori:0;in;i{fmt.Scan(prices[i])// 循环读取n个价格到数组}// 计算并打印最大利润res:maxProfit(prices)fmt.Println(res)}// 或funcmain(){varprices[]intvarnumint// 循环不断读取int只要成功读到1个整数就继续读到非数字/输入结束则退出循环forfmt.Scan(num)1{pricesappend(prices,num)}res:maxProfit(prices)fmt.Println(res)}/* 测试用例1 【输入】7 1 5 3 6 4 【预期输出】5 解释买入价格1卖出价格6最大利润 5时间复杂度O (n)仅遍历一次价格数组空间复杂度O (1)仅使用常数个变量packagemainimportfmt// maxProfit 返回最大利润[买入价,卖出价]funcmaxProfit(prices[]int)(int,[2]int){n:len(prices)ifn2{return0,[2]int{0,0}}minPrice:prices[0]// 历史最低价格buyPrice:0sellPrice:0maxProfitVal:0fori:1;in;i{// 更新历史最低点可以在这里买ifprices[i]minPrice{minPriceprices[i]}else{// 在今天卖出算利润profit:prices[i]-minPriceifprofitmaxProfitVal{maxProfitValprofit buyPriceminPrice sellPriceprices[i]}}}ifmaxProfitVal0{return0,[2]int{0,0}}returnmaxProfitVal,[2]int{buyPrice,sellPrice}}funcmain(){prices:[]int{7,2,5,9,1,3,6,4}profit,pair:maxProfit(prices)fmt.Printf(%d, %v\n,profit,pair)// 输出7, [2 9] 和样例完全一致}读取单个数字 / 字符串fmt.Scan(变量名)varnint// 定义一个整数变量nfmt.Scan(n)// 终端输入一个数字比如6n就等于6varsstringfmt.Scan(s)// 终端输入一个字符串s就等于该字符串循环读取多个值for循环 fmt.Scan(数组元素)// 步骤1定义变量接收数组长度读取长度n 【必须加】varnintfmt.Scan(n)// 步骤2初始化一个长度为n的切片/数组 【固定写法】nums:make([]int,n)// 切片算法面试首选比数组灵活// 步骤3循环n次读取n个数字存入切片 【必须加nums[i]】fori:0;in;i{fmt.Scan(nums[i])// 每次读取一个数字赋值给nums[i]}读取两个数字vara,bintfmt.Scan(a,b)// 终端输入3 5a3b5fmt.Println(ab)// 输出8122.买卖股票的最佳时机II题目给你一个整数数组 prices 其中 prices[i] 表示某支股票第 i 天的价格。在每一天你可以决定是否购买和/或出售股票。你在任何时候最多只能持有一股股票。然而你可以在同一天多次买卖该股票但要确保你持有的股票不超过一股。返回你能获得的最大利润 。示例 1输入prices [7,1,5,3,6,4]输出7解释在第 2 天股票价格 1的时候买入在第 3 天股票价格 5的时候卖出, 这笔交易所能获得利润 5 - 1 4。随后在第 4 天股票价格 3的时候买入在第 5 天股票价格 6的时候卖出, 这笔交易所能获得利润 6 - 3 3。最大总利润为 4 3 7 。示例 2输入prices [1,2,3,4,5]输出4解释在第 1 天股票价格 1的时候买入在第 5 天 股票价格 5的时候卖出, 这笔交易所能获得利润 5 - 1 4。最大总利润为 4 。示例 3输入prices [7,6,4,3,1]输出0解释在这种情况下, 交易无法获得正利润所以不参与交易可以获得最大利润最大利润为 0。提示1 prices.length 3 * 10^40 prices[i] 10^4思路只要后一天股价 前一天股价就在前一天买入、后一天卖出赚取该段差价股价下跌/持平则不操作。最终所有上涨差价的总和就是最大利润。为什么“只赚相邻上涨差价”是最优的1数学等价性拆分交易 长期持有对于任意持续上涨区间prices[i] prices[i1] ... prices[j]拆分交易利润(prices[i1]-prices[i]) (prices[i2]-prices[i1]) ... (prices[j]-prices[j-1])单次长期交易利润prices[j] - prices[i]两者展开后中间项完全抵消最终结果相等比如1→2→3→4→5拆分赚11114长期持有赚5-14。这意味着“每天买卖赚小差价”只是数学上的等价拆解并非真的要高频操作实际可简化为“低点买、高点卖”利润完全一致。2覆盖所有盈利可能无遗漏相邻天数的判断能精准捕捉所有独立上涨区间比如7,1,5,3,6,4中的1→5、3→6不会放过任何可盈利的差价而“跳天判断”要么不可行中间下跌时持有会亏损要么利润与相邻判断相等无任何优势。举个反例如果股价是[1,3,2,4]有人觉得 “1 买 4 卖”利润 3比 “1 买 3 卖、2 买 4 卖”利润 224更优→ 错“1 买 4 卖” 的实际操作中3→2 下跌时持有股票相当于 “赚了 1→3 的 2亏了 3→2 的 1赚了 2→4 的 2”总利润 2-123反而比相邻贪心的 4 少 —— 这就是 “跳天操作” 的问题中间下跌会吃掉部分利润而相邻贪心会在下跌前卖出避免亏损。具体步骤初始化定义maxProfit 0用于累加总利润遍历数组从第2天索引1开始逐个对比当天与前一天的股价若prices[i] prices[i-1]将prices[i] - prices[i-1]加到maxProfit若prices[i] ≤ prices[i-1]不操作利润保持不变返回结果遍历结束后maxProfit即为最大利润全程下跌时利润为0符合题目要求。举例示例1prices [7,1,5,3,6,4]1→5差价4 →maxProfit43→6差价3 →maxProfit7其余天数下跌/持平无操作最终利润7与示例一致。示例2prices [1,2,3,4,5]每天差价1累加得4 → 与“1买5卖”利润一致。示例3prices [7,6,4,3,1]所有天数股价下跌利润保持0。代码实现GopackagemainimportfmtfuncmaxProfit(prices[]int)int{maxProfit:0// 从第2天索引1开始遍历对比当天与前一天的股价// 索引0是第1天无前置价格无需处理fori:1;ilen(prices);i{ifprices[i]prices[i-1]{// 若当天价格 前一天价格赚取该段差价maxProfitprices[i]-prices[i-1]}// 价格下跌/持平时不操作利润保持不变无需额外处理}returnmaxProfit}funcmain(){varnintfmt.Scan(n)prices:make([]int,n)fori:0;in;i{fmt.Scan(prices[i])}res:maxProfit(prices)fmt.Println(res)}时间复杂度O (n)仅遍历一次价格数组空间复杂度O (1)仅使用 maxProfit 一个变量进阶思路动态规划1. 状态定义dp[i][0]第i天不持有股票的最大利润dp[i][1]第i天持有股票的最大利润。2. 状态转移不持有股票要么前一天也不持有要么前一天持有、今天卖出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])。dp[i][0]卖出操作会让利润增加prices[i]取「不操作」和「卖出」中利润更大的情况dp[i][1]买入操作会让利润减少-prices[i]取「不操作」和「买入」中利润更大的情况3. 初始状态dp[0][0] 0第0天不持有利润0dp[0][1] -prices[0]第0天买入利润为负。4. 最终结果dp[n-1][0]最后一天不持有股票的利润必然高于持有。代码实现GopackagemainimportfmtfuncmaxProfit(prices[]int)int{n:len(prices)// 边界处理如果价格数组为空直接返回0ifn0{return0}// 定义dp数组dp[i][0]表示第i天不持有股票的最大利润dp[i][1]表示持有dp:make([][2]int,n)// 初始状态第0天第一天的状态dp[0][0]0// 第0天不持有股票利润为0dp[0][1]-prices[0]// 第0天买入股票利润为 -股价成本// 遍历从第1天开始索引1逐天更新状态fori:1;in;i{// 状态转移1第i天不持有股票的两种情况// 情况1前一天也不持有利润不变情况2前一天持有今天卖出利润前一天持有利润今天股价dp[i][0]max(dp[i-1][0],dp[i-1][1]prices[i])// 状态转移2第i天持有股票的两种情况// 情况1前一天也持有利润不变情况2前一天不持有今天买入利润前一天不持有利润-今天股价dp[i][1]max(dp[i-1][1],dp[i-1][0]-prices[i])}// 最终结果最后一天不持有股票的利润持有股票的话未卖出利润必然更低returndp[n-1][0]}funcmax(a,bint)int{ifab{returna}returnb}funcmain(){varnintfmt.Scan(n)prices:make([]int,n)fori:0;in;i{fmt.Scan(prices[i])}res:maxProfit(prices)fmt.Println(res)}时间复杂度O (n)仅遍历一次价格数组空间复杂度O (n)创建了长度为 n、每个元素为长度 2 的数组 dp空间优化滚动数组O (1) 空间上述代码用了 O (n) 空间实际可优化为 O (1)因为每天的状态仅依赖前一天适合大数据量场景代码实现GopackagemainimportfmtfuncmaxProfit(prices[]int)int{n:len(prices)// 边界处理如果价格数组为空直接返回0ifn0{return0}// 用两个变量代替dp数组滚动更新hold:-prices[0]// 持有股票的最大利润初始为第0天买入notHold:0// 不持有股票的最大利润初始为第0天不操作fori:1;in;i{// 先保存更新前的状态避免覆盖preHold:hold preNotHold:notHold// 更新不持有状态前一天不持有 或 前一天持有今天卖出notHoldmax(preNotHold,preHoldprices[i])// 更新持有状态前一天持有 或 前一天不持有今天买入holdmax(preHold,preNotHold-prices[i])}returnnotHold}funcmain(){varnintfmt.Scan(n)prices:make([]int,n)fori:0;in;i{fmt.Scan(prices[i])}res:maxProfit(prices)fmt.Println(res)}时间复杂度O (n)仅遍历一次价格数组空间复杂度O (1)

相关新闻

基于Springboot供应商管理系统【附源码+文档】

基于Springboot供应商管理系统【附源码+文档】

💕💕作者: 米罗学长 💕💕个人简介:混迹java圈十余年,精通Java、小程序、数据库等。 💕💕各类成品Java毕设 。ssm,springboot,vue等项目&#xff0…

2026/10/14 2:32:25 阅读更多 →
【单片机毕业设计】基于STM32的婴儿床多参数监测与摄像头远程监护装置设计 基于物联网的婴儿监护摇篮生理环境监测与联动控制系统设计(032709)

【单片机毕业设计】基于STM32的婴儿床多参数监测与摄像头远程监护装置设计 基于物联网的婴儿监护摇篮生理环境监测与联动控制系统设计(032709)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

2026/10/14 2:32:25 阅读更多 →
VT-System硬件在环测试实战:从板卡选型到CAPL脚本排坑指南

VT-System硬件在环测试实战:从板卡选型到CAPL脚本排坑指南

简介:Vector VT-System 中文使用手册由 Vector 官方发布,面向汽车电子测试工程师、HiL 测试人员与 CANoe 使用者,是一份聚焦 VT 板卡实际部署的中文参考资料。围绕板卡选型、安装、供电、接地、配置与排错,系统梳理了不同板卡类型…

2026/10/14 2:31:25 阅读更多 →

最新新闻

补码运算核心技巧全解析

补码运算核心技巧全解析

一、运算方法(定点数、浮点数运算)(一)定点数运算 1. 原码 原码表示:符号位数值位,正数符号0,负数符号1 加法:符号相同,数值相加;符号不同,大数减…

2026/10/14 3:20:34 阅读更多 →
Kali/Ubuntu离线安装GCC:从裸机到可编译环境的完整路径

Kali/Ubuntu离线安装GCC:从裸机到可编译环境的完整路径

1. 为什么“在Kali/Ubuntu里装GCC”会变成一个真问题?很多人第一次看到这个标题,第一反应是:“这不就是apt install build-essential一行命令的事?还用专门写篇博文?”我完全理解这种困惑——毕竟在绝大多数标准安装的…

2026/10/14 3:20:34 阅读更多 →
VS Code 的 `code` 命令:一个让你可以偷懒的神器

VS Code 的 `code` 命令:一个让你可以偷懒的神器

打开项目这件事,键盘比鼠标快十倍。前提是你得先把 code 命令装进 PATH。 先解决一个尴尬:你敲 code 可能没反应 在终端里输入 code .,如果系统回你一句“code 不是内部或外部命令”,不是你敲错了,是 VS Code 的 code …

2026/10/14 3:20:34 阅读更多 →
C++编译器优化实战:从-O2到链接时优化的性能调优地图

C++编译器优化实战:从-O2到链接时优化的性能调优地图

1. 优化全貌:编译器在后台做的事写 C 的人,多多少少都听过“编译器优化”这五个字,但真正把这五个字当成设计输入的人并不多。我对编译器优化的理解转折点,来自于一次性能排查:同一段数值计算,只是把优化选…

2026/10/14 3:20:34 阅读更多 →
Linux虚拟文件系统解析:/proc /sys /dev的核心原理与运维实战

Linux虚拟文件系统解析:/proc /sys /dev的核心原理与运维实战

前两天,我一个后端的同事跑过来问了我一个特别基础但又让人一时语塞的问题:新装的一台 Linux 机器上,根目录里那几个dev、sys、proc到底是不是真的文件夹?他说用du -sh /proc看一眼占用不到 1M,但里面文件又多得离谱&a…

2026/10/14 3:20:34 阅读更多 →
2026年普通人副业指南:从AI工具到个人IP的完整变现路径

2026年普通人副业指南:从AI工具到个人IP的完整变现路径

刷到“2026年不可不知的副业路子,月入过万不是梦”这种标题,大家第一反应基本都是“又来割韭菜了”。说实话,我以前也这么想,直到自己真的把副业从月入几百做到稳定过万,才意识到这类标题下的内容,至少有一…

2026/10/14 3:19:34 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →