题目描述:
给定一个数组
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。
解题思路:
方法一:贪心(维护最低价格)
核心思路:
对于每一天,如果在这一天卖出,最大利润 =当天价格 - 之前的最低价格。
所以只需要:
维护历史最低价格
minPrice每天计算
prices[i] - minPrice,更新最大利润更新
minPrice = min(minPrice, prices[i])
具体过程示例:
prices = [7,1,5,3,6,4]
| i | prices[i] | minPrice | 当天利润 | maxProfit |
|---|---|---|---|---|
| 0 | 7 | 7 | 0 | 0 |
| 1 | 1 | 1 | 0 | 0 |
| 2 | 5 | 1 | 4 | 4 |
| 3 | 3 | 1 | 2 | 4 |
| 4 | 6 | 1 | 5 | 5 |
| 5 | 4 | 1 | 3 | 5 |
结果:5✅
代码实现:
class Solution { public: int maxProfit(vector<int>& prices) { int minPrice = INT_MAX; int maxProfit = 0; for (int price : prices) { if (price < minPrice) { minPrice = price; // 更新最低价格 } else { maxProfit = max(maxProfit, price - minPrice); // 更新最大利润 } } return maxProfit; } };更简洁的写法:
class Solution { public: int maxProfit(vector<int>& prices) { int minPrice = INT_MAX, maxProfit = 0; for (int price : prices) { minPrice = min(minPrice, price); maxProfit = max(maxProfit, price - minPrice); } return maxProfit; } };复杂度分析:
| 维度 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | 一次遍历 |
| 空间复杂度 | O(1) | 只用两个变量 |
关键细节:
1. 为什么maxProfit初始为 0?
因为如果股票一直跌,不买就是最大利润(0),不会亏本。
2. 为什么先更新minPrice再计算利润?
因为买入必须在卖出之前。先更新minPrice保证用的是今天之前的最低价格。
cpp
minPrice = min(minPrice, price); // 先更新最低价 maxProfit = max(maxProfit, price - minPrice); // 再算利润
如果反过来,可能会用当天的价格买入和卖出,利润为 0,逻辑不对。
3. 和「买卖股票的最佳时机 II」的区别
| 题目 | 区别 |
|---|---|
| 121. 买卖股票 I | 只能买卖一次 |
| 122. 买卖股票 II | 可以买卖多次 |
122 题:只要后一天比前一天高,就累加利润。
方法二:动态规划
思路:
维护两个状态:
dp[i][0]:第 i 天不持有股票的最大利润dp[i][1]:第 i 天持有股票的最大利润
代码实现:
class Solution { public: int maxProfit(vector<int>& prices) { int n = prices.size(); vector<vector<int>> dp(n, vector<int>(2, 0)); dp[0][0] = 0; // 不持有 dp[0][1] = -prices[0]; // 持有(买入) for (int i = 1; i < n; i++) { 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]; } };空间优化:
class Solution { public: int maxProfit(vector<int>& prices) { int hold = -prices[0]; // 持有股票 int notHold = 0; // 不持有股票 for (int i = 1; i < prices.size(); i++) { notHold = max(notHold, hold + prices[i]); // 卖出 hold = max(hold, -prices[i]); // 买入 } return notHold; } };复杂度:时间 O(n),空间 O(1)
两种方法对比:
| 方法 | 时间复杂度 | 空间复杂度 | 推荐度 |
|---|---|---|---|
| 贪心(维护最低价) | O(n) | O(1) | ⭐⭐⭐⭐⭐ |
| 动态规划 | O(n) | O(1) | ⭐⭐⭐⭐ |
总结:
| 要点 | 说明 |
|---|---|
| 核心思想 | 维护历史最低价,每天计算利润 |
| 关键操作 | minPrice = min(minPrice, price); maxProfit = max(maxProfit, price - minPrice); |
| 时间复杂度 | O(n) |
| 空间复杂度 | O(1) |