1 题目
给定一个数组 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 <= 1050 <= prices[i] <= 104
2 代码实现
cpp
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
if (n == 0){
return 0 ;
}
int maxPro = 0 ;
int minP = prices[0];
for (int i = 0 ; i < n ; i ++){
int curPro = prices[i] - minP;
maxPro = max (maxPro ,curPro);
minP = min( minP, prices[i]);
}
return maxPro;
}
};
自己乱七八糟写
能通过部分测试用例但执行出错。。
cpp
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
int curPro = 0 ;
int maxPro = 0 ;
for (int i = 0 ; i < n ; i++){
for (int j = n ; j > i ; j--){
curPro = prices[j] - prices[i] ;
curPro > 0 ? curPro : 0 ;
maxPro = max(curPro,maxPro);
}
}
return maxPro;
}
};
你的代码能通过部分测试用例但执行出错,核心问题是数组越界访问 + 逻辑冗余 / 效率问题,以下是详细分析和修正方案:
一、核心错误:数组下标越界
在你的内层循环中:
cpp
for (int j = n ; j > i ; j--) {
curPro = prices[j] - prices[i] ; // 致命错误:j初始值为n,超出数组范围
}
- 数组
prices的合法下标范围是0 ~ n-1(因为n = prices.size()); - 当
j = n时,prices[j]访问的是数组不存在的位置,会触发「数组越界访问」错误(运行时崩溃); - 你可能想写
j = n-1,但即使修正这个,双重循环的时间复杂度是O(n²),对于大数组(比如 n=10⁵)会超时。
二、次要问题:逻辑冗余
cpp
curPro > 0 ? curPro : 0 ; // 这行代码没有任何效果!
三元运算符的结果没有赋值给curPro,等价于 "白判断",正确写法是:
cpp
curPro = curPro > 0 ? curPro : 0; // 或者 curPro = max(curPro, 0);
三、修正方案(最优解:一次遍历,O (n) 时间)
"买卖股票的最佳时机" 问题的最优思路是:遍历过程中记录当前最小价格,同时计算当前价格与最小价格的差值,更新最大利润。
修正后的代码:
cpp
class Solution {
public:
int maxProfit(vector<int>& prices) {
if (prices.empty()) return 0; // 空数组直接返回0
int minPrice = prices[0]; // 记录遍历到当前的最小价格
int maxPro = 0; // 记录最大利润
for (int i = 1; i < prices.size(); ++i) {
// 计算当前卖出能获得的利润
int curPro = prices[i] - minPrice;
// 更新最大利润(利润为负则取0)
maxPro = max(maxPro, curPro);
// 更新最小价格(如果当前价格更低)
minPrice = min(minPrice, prices[i]);
}
return maxPro;
}
};
四、原代码的其他问题说明
即使修正下标越界(把j = n改成j = n-1),仍存在以下问题:
- 时间复杂度太高:双重循环对大数组(如 LeetCode 的极端测试用例)会超时;
- 逻辑冗余:内层循环从后往前遍历完全没必要,且重复计算大量无效差值;
- 边界处理缺失 :如果
prices为空数组,n=0,内层循环不会执行,但代码本身能返回 0,这一点是幸运的,但最好显式处理空数组。
五、测试用例验证
| 测试用例 | 原代码(修正下标前) | 原代码(修正下标后) | 最优解 |
|---|---|---|---|
| [7,1,5,3,6,4] | 崩溃(越界) | 5(正确) | 5 |
| [7,6,4,3,1] | 崩溃(越界) | 0(正确) | 0 |
| [] | 0(侥幸正确) | 0(正确) | 0 |
| [1,2] | 崩溃(越界) | 1(正确) | 1 |
| [10⁵个元素] | 崩溃 / 超时 | 超时 | 快速通过 |
综上,你的代码执行出错的核心原因是数组下标越界,即使修正下标,也会因时间复杂度太高导致超时,建议使用一次遍历的最优解法。
3 题目
给你一个下标从 0 开始的整数数组 nums ,该数组的大小为 n ,请你计算 nums[j] - nums[i] 能求得的 最大差值 ,其中 0 <= i < j < n 且 nums[i] < nums[j] 。
返回 最大差值 。如果不存在满足要求的 i 和 j ,返回 -1 。
示例 1:
输入:nums = [7,1,5,4]
输出:4
解释:
最大差值出现在 i = 1 且 j = 2 时,nums[j] - nums[i] = 5 - 1 = 4 。
注意,尽管 i = 1 且 j = 0 时 ,nums[j] - nums[i] = 7 - 1 = 6 > 4 ,但 i > j 不满足题面要求,所以 6 不是有效的答案。
示例 2:
输入:nums = [9,4,3,2]
输出:-1
解释:
不存在同时满足 i < j 和 nums[i] < nums[j] 这两个条件的 i, j 组合。
示例 3:
输入:nums = [1,5,2,10]
输出:9
解释:
最大差值出现在 i = 0 且 j = 3 时,nums[j] - nums[i] = 10 - 1 = 9 。
提示:
n == nums.length2 <= n <= 10001 <= nums[i] <= 109
4 代码实现
cpp
class Solution {
public:
int maximumDifference(vector<int>& nums) {
int n = nums.size();
if (n < 2 ){
return -1 ;
}
int minNum = nums[0];
int maxDiff = -1 ;
for (int i = 1; i < n ; i ++){
minNum = min (minNum , nums[i - 1]);
int diff = nums[i] - minNum ;
if (diff > 0 ){
maxDiff = max(maxDiff,diff);
}
}
return maxDiff;
}
};
错错错,是我的错 !
cpp
class Solution {
public:
int maximumDifference(vector<int>& nums) {
int n = nums.size();
if (n < 3 ){
return -1 ;
}
int minNum = nums[0];
int maxDiff = -1 ;
for (int i = 0; i < n ; i ++){
int diff = nums[i] - minNum ;
maxDiff = max(maxDiff,diff);
minNum = min(minNum , nums[i]);
}
return maxDiff;
}
};
要找出这段代码的错误,我们先明确题目核心要求(最大差值问题的关键规则),再逐一分析问题:
第一步:明确题目真正要求
题目maximumDifference的核心规则(LeetCode 2016 题):
找出数组中两个元素
nums[j] - nums[i]的最大差值 ,满足i < j且nums[j] > nums[i];如果不存在这样的数对,返回-1。
你的代码存在 3 个核心错误,下面逐一拆解:
错误 1:错误的边界条件(n < 3 返回 - 1)
题目要求只要数组长度≥2 就可以找 i<j 的数对(比如[1,2]应该返回 1),但你代码中判断n < 3就返回 - 1,直接错误过滤了长度为 2 的合法情况。
cpp
if (n < 3 ){ return -1 ; } // 错误!正确应该是 n < 2 才返回-1(甚至n=2也能判断)
错误 2:逻辑顺序错误(先算差值再更新最小值)
你的代码中,先计算当前数与 minNum 的差值,再更新 minNum,这会导致:
- 当
i=0时,diff = nums[0] - minNum(nums[0])= 0,会把maxDiff从 - 1 更新为 0; - 但题目要求
nums[j] > nums[i](差值必须 > 0),0 是不合法的; - 更严重的是:如果数组是
[5,4,3,2,1],你的代码会返回 0(而非 - 1),违反题目要求。
正确逻辑应该是:先更新最小值(保证 minNum 是 i 之前的数),再计算当前数与 minNum 的差值(且只保留 > 0 的差值)。
错误 3:未过滤差值≤0 的情况
即使修正了逻辑顺序,若数组是严格递减的(如[5,4,3]),所有差值都是≤0 的,此时应返回 - 1,但你的代码会保留 0 或负数,导致错误。
修正后的代码
cpp
class Solution {
public:
int maximumDifference(vector<int>& nums) {
int n = nums.size();
if (n < 2) { // 错误1:修正边界条件(长度<2才无意义)
return -1;
}
int minNum = nums[0]; // 初始最小值为第一个元素
int maxDiff = -1; // 初始最大差值为-1(无合法数对时返回)
// 从第二个元素开始遍历(i=1,保证i>0,即j>i)
for (int i = 1; i < n; ++i) {
// 错误2:先更新最小值(minNum是i之前的数,保证i<j)
minNum = min(minNum, nums[i-1]);
// 计算当前数与minNum的差值,且只保留>0的情况
int diff = nums[i] - minNum;
if (diff > 0) { // 错误3:过滤≤0的差值
maxDiff = max(maxDiff, diff);
}
}
return maxDiff;
}
};
测试用例验证
| 输入数组 | 错误代码输出 | 修正代码输出 | 正确结果 |
|---|---|---|---|
| [1,2] | -1 | 1 | 1 |
| [5,4,3,2,1] | 0 | -1 | -1 |
| [7,1,5,4] | 4 | 4 | 4 |
| [9,4,3,2] | 0 | -1 | -1 |
核心总结
- 边界条件:数组长度≥2 才有可能有合法差值,而非≥3;
- 逻辑顺序:先更新 "i 之前的最小值",再计算当前数与最小值的差值,保证
i<j; - 差值过滤:只保留 > 0 的差值,无合法差值时返回 - 1。