Leetcode 71 买卖股票的最佳时机 | 增量元素之间的最大差值

1 题目

121. 买卖股票的最佳时机

给定一个数组 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 <= 105
  • 0 <= 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),仍存在以下问题:

  1. 时间复杂度太高:双重循环对大数组(如 LeetCode 的极端测试用例)会超时;
  2. 逻辑冗余:内层循环从后往前遍历完全没必要,且重复计算大量无效差值;
  3. 边界处理缺失 :如果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 题目

2016. 增量元素之间的最大差值

给你一个下标从 0 开始的整数数组 nums ,该数组的大小为 n ,请你计算 nums[j] - nums[i] 能求得的 最大差值 ,其中 0 <= i < j < nnums[i] < nums[j]

返回 最大差值 。如果不存在满足要求的 ij ,返回 -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.length
  • 2 <= n <= 1000
  • 1 <= 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 < jnums[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

核心总结

  1. 边界条件:数组长度≥2 才有可能有合法差值,而非≥3;
  2. 逻辑顺序:先更新 "i 之前的最小值",再计算当前数与最小值的差值,保证i<j
  3. 差值过滤:只保留 > 0 的差值,无合法差值时返回 - 1。
相关推荐
霸王大陆1 小时前
《零基础学PHP:从入门到实战》教程-模块八:面向对象编程(OOP)入门-5
开发语言·笔记·php·课程设计
0 0 01 小时前
CCF-CSP 37-3 模板展开(templating)【C++】
c++·算法
摇滚侠1 小时前
2025最新 SpringCloud 教程,接口测试,本地事务,打通链路,笔记65,笔记66,笔记67
笔记·spring·spring cloud
DevangLic1 小时前
【win的实用官方工具集合】解决:该设备正在使用中,请关闭所有。。。
运维·学习·工具
永远都不秃头的程序员(互关)1 小时前
鸿蒙Electron平台:Flutter技术深度解读及学习笔记
笔记·学习·flutter
bulingg1 小时前
聚类方法(kmeans,DBSCAN,层次聚类,GMM,EM算法)
算法·kmeans·聚类
思成不止于此1 小时前
MySQL 查询进阶(二):行筛选与条件查询
数据库·笔记·学习·mysql
lally.1 小时前
Kaggle Binary Classification with a Bank Dataset逻辑回归实现(准确率0.94539)
人工智能·算法·机器学习·逻辑回归
埃伊蟹黄面1 小时前
二分查找算法
c++·算法·leetcode