)
示例工程【免费下载链接】leetcodeLeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer第 2 版》、《程序员面试金典第 6 版》题解项目地址https://gitcode.com/doocs/leetcode点击查看免费下载本篇技术指南围绕《剑指 Offer第 2 版》面试题 63「股票的最大利润」展开它是 LeetCode 主站第 121 题「Best Time to Buy and Sell Stock」的同题版本也是买卖股票系列中最基础、最常被面试官考察的动态规划入门题。本文以 doocs/leetcode 仓库中该题的 README 文档 为骨架结合仓库内 Python3、Java、C、Go、TypeScript、Rust、JavaScript、C#、Swift 共 9 种语言的 Solution 实现完整讲解一次遍历求解思路、边界情况处理与复杂度分析读者读完后可直接掌握该类区间最优买卖问题的通用解法并对照仓库源码加深理解。题目描述假设把某股票的价格按照时间先后顺序存储在数组中请问买卖该股票一次可能获得的最大利润是多少示例 1输入: [7,1,5,3,6,4] 输出: 5 解释: 在第 2 天股票价格 1的时候买入在第 5 天股票价格 6的时候卖出最大利润 6-1 5。 注意利润不能是 7-1 6因为卖出价格需要大于买入价格。示例 2输入: [7,6,4,3,1] 输出: 0 解释: 在这种情况下没有交易完成所以最大利润为 0。限制0 数组长度 10^5注意本题与主站第 121 题相同属于买卖股票系列Best Time to Buy and Sell Stock中最基础的只能交易一次模型。题意分析与核心思路先明确三个关键约束它们直接决定了算法的形态只能买卖一次买入必须发生在卖出之前先买后卖买入日是卖出日之前的某一天价格数组按时间排序prices[i]表示第i1天的价格下标即时间轴无交易也算合法结果当所有天价格单调递减时任何先买后卖都会亏损此时最优策略是不交易最大利润为0这正是示例 2 的情况。基于这些约束一个直观但低效的做法是枚举所有买入日 卖出日对平方级不可取。注意到一个关键观察固定某一天作为卖出日时要使利润最大买入日必然是这一天之前价格最低的那一天。也就是说对每个下标i若记录i之前含i之前所有天出现的最低价格mi则在第i天卖出可获得的最大利润为prices[i] - mi全局答案就是所有这样的利润取最大值。这个思路把枚举买卖日对降维成枚举卖出日 维护历史最低买入价只需从左到右扫描一遍数组这正是本题的标准解法。方法一一次遍历维护最低价与最大利润算法流程初始化变量mi为历史最低价格初始值应为一个足够大的数如正无穷保证第一次计算x - mi不会产生错误结果初始化答案变量ans 0对应不交易这一保底选择从左到右遍历价格数组prices用当前价格x更新答案ans max(ans, x - mi)即以x为卖出价、此前最低价mi为买入价得到的利润用当前价格x更新历史最低价mi min(mi, x)为后续天数的卖出做铺垫。循环结束后ans即为最大利润。由于初始化ans 0即使全程价格单调递减示例 2 的[7,6,4,3,1]x - mi始终为负ans保持为0天然覆盖了不交易的情况无需额外分支判断。复杂度分析时间复杂度 O(n)只需一次线性扫描n为数组prices的长度空间复杂度 O(1)仅使用两个常数级别的变量mi与ans。在0 数组长度 10^5的限制下该解法可以轻松通过。正确性论证假设全局最优交易为第b天买入、第s天卖出b s那么在第s天被扫描到时mi一定不大于prices[b]因为b sprices[b]已经被纳入mi的更新范围于是prices[s] - mi prices[s] - prices[b]即扫描到第s天时计算出的候选利润不会小于全局最优利润。而ans会取所有候选利润的最大值因此ans必然不小于全局最优利润另一方面任何候选利润x - mi都对应一个合法的此前某天买入、当天卖出交易不会超过全局最优利润。两者结合即得ans恰好等于最大利润。多语言实现仓库在 lcof/面试题63. 股票的最大利润/ 目录下为本题提供了 9 种语言的独立可运行实现逻辑完全一致mi或min维护历史最低价ans或res维护最大利润。各语言的具体差异主要体现在无穷大/极大值的表示方式上Python3使用inf表示正无穷Java / C / Go / JavaScript / C#使用1 30即 2^30约 10.7 亿作为足够大的初始值。由于题目限制数组长度最大 10^5 且股价为常规整数1 30远大于任何可能的价格差可作为虚拟正无穷TypeScript / Rust / Swift分别使用Infinity、i32::MAX、Int.max作为语言内的最大值表示。Python3完整实现见 Solution.pyclass Solution: def maxProfit(self, prices: List[int]) - int: mi, ans inf, 0 for x in prices: ans max(ans, x - mi) mi min(mi, x) return ansJava完整实现见 Solution.javaclass Solution { public int maxProfit(int[] prices) { int mi 1 30, ans 0; for (int x : prices) { ans Math.max(ans, x - mi); mi Math.min(mi, x); } return ans; } }C完整实现见 Solution.cppclass Solution { public: int maxProfit(vectorint prices) { int mi 1 30, ans 0; for (int x : prices) { ans max(ans, x - mi); mi min(mi, x); } return ans; } };Go完整实现见 Solution.go。这里使用了 Go 内置泛型函数max/min需 Go 1.21并利用命名返回值(ans int)在函数末尾直接returnfunc maxProfit(prices []int) (ans int) { mi : 1 30 for _, x : range prices { ans max(ans, x-mi) mi min(mi, x) } return }TypeScript完整实现见 Solution.tsfunction maxProfit(prices: number[]): number { let res 0; let min Infinity; for (const price of prices) { res Math.max(res, price - min); min Math.min(min, price); } return res; }Rust完整实现见 Solution.rsimpl Solution { pub fn max_profit(prices: Veci32) - i32 { let mut res 0; let mut min i32::MAX; for price in prices { res res.max(price - min); min min.min(price); } res } }JavaScript完整实现见 Solution.js/** * param {number[]} prices * return {number} */ var maxProfit function (prices) { let mi 1 30; let ans 0; for (const x of prices) { ans Math.max(ans, x - mi); mi Math.min(mi, x); } return ans; };C#完整实现见 Solution.cspublic class Solution { public int MaxProfit(int[] prices) { int mi 1 30; int ans 0; foreach(int x in prices) { ans Math.Max(ans, x - mi); mi Math.Min(mi, x); } return ans; } }Swift完整实现见 Solution.swiftclass Solution { func maxProfit(_ prices: [Int]) - Int { var mi Int.max var ans 0 for x in prices { ans max(ans, x - mi) mi min(mi, x) } return ans } }边界情况与易错点对照两个官方示例与限制条件重点注意以下细节空数组数组长度的下限为0。当prices为空时循环体一次都不执行ans保持初始值0直接返回无需额外判空严格递减序列如[7,6,4,3,1]所有x - mi均为负数但ans初始化为0保证了不交易这一最优选择被正确返回不能把ans初始化为-inf或某一天的价格否则空数组/全跌场景会得到错误答案先更新 ans 还是先更新 mi 的顺序必须先计算x - mi用旧的最低买入价再执行mi min(mi, x)。若顺序颠倒x被先写入mi则x - mi恒为 0会丢失当天之前的最低价买入这一信息——虽然本题结果不受影响因为可以当天买卖不产生利润等价于不交易但语义上不正确且在其他变体题中会引入错误mi初始值的选取Java/C/Go/JavaScript/C# 中1 30是足够大的安全初值Python 用inf、Rust 用i32::MAX、Swift 用Int.max、TypeScript 用Infinity均保证第一次x - mi计算不会产生异常值。与主站 121 题及买卖股票系列的关系本题在《剑指 Offer》中是第 63 题与 LeetCode 主站第 121 题Best Time to Buy and Sell Stock完全相同仓库 lcof/lcof.json 中该题ID 100344的元数据也将其标记为「动态规划」Dynamic Programming、难度「中等」归属于lcof剑指 Offer分类。这一题是整个买卖股票系列的第一环系列后续题目在它基础上逐步增加约束解题思路随之升级只能交易一次本题 / 121 题一次遍历维护最低价O(n) 时间、O(1) 空间可以交易多次122 题累计所有上涨段的差价贪心即可最多交易两次123 题、最多交易 k 次188 题引入二维状态动态规划含冷冻期309 题、含手续费714 题在状态转移中加入冷冻/费用的维度。从源码结构看doocs/leetcode 仓库在 solution 目录下按题号区间维护了主站题解如 solution/0100-0199而 lcof、lcci、lcof2、lcp 等目录分别对应剑指 Offer、程序员面试金典、剑指 Offer 专项突击版与 LCP 系列同一算法模型在不同题集间互相印证非常适合对照学习。总结「股票的最大利润」虽然被标记为动态规划类题目但其最优解本质上是一趟线性扫描用mi记录历史最低买入价、用ans记录截至当前的最高利润两者交替更新即可在 O(n) 时间内得到答案空间开销为 O(1)。理解固定卖出日、最优买入即此前最低价这一核心观察是掌握本题乃至整个买卖股票系列的关键。仓库为该题提供的 README 题解 与 9 种语言实现Solution.py、Solution.java、Solution.cpp、Solution.go、Solution.ts、Solution.rs、Solution.js、Solution.cs、Solution.swift可直接作为刷题与面试准备时的参考模板。赞分享示例工程【免费下载链接】leetcodeLeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer第 2 版》、《程序员面试金典第 6 版》题解项目地址https://gitcode.com/doocs/leetcode点击查看免费下载相关推荐CS-Notes 剑指 Offer 题解股票的最大利润贪心法 O(n) 求单次交易最大收益CS Notes 剑指 Offer 题解股票的最大利润贪心法 O n 求单次交易最大收益 本篇基于 63. 股票的最大利润 展开完整讲解一次买入 一文档教程知识库AlgoNote 题解LeetCode 0121 买卖股票的最佳时机——一次遍历递推求解最大利润AlgoNote 题解LeetCode 0121 买卖股票的最佳时机——一次遍历递推求解最大利润 导读 本篇题解基于「算法通关手册」AlgoNote仓库中教程教育LeetCode-Book · 剑指 Offer 63 股票的最大利润从 O(N²) 暴力枚举到 O(N) 动态规划与空间压缩LeetCode Book · 剑指 Offer 63 股票的最大利润从 O N² 暴力枚举到 O N 动态规划与空间压缩 本文基于 LeetCode Boo示例工程教程教育上一篇radare2 发布流程与版本管理指南从发布规则到发行包生成全解析下一篇Easy Dataset社区贡献者访谈背后的开发故事与经验分享创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考