【动态规划-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. 维护历史最低价格 minPrice

  2. 每天计算 prices[i] - minPrice,更新最大利润

  3. 更新 minPrice = min(minPrice, prices[i])

具体过程示例:

prices = [7,1,5,3,6,4]

i pricesi 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 ✅

代码实现:

cpp 复制代码
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;
    }
};

更简洁的写法:

cpp 复制代码
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),不会亏本。

  1. 为什么先更新 minPrice 再计算利润?

因为买入必须在卖出之前。先更新 minPrice 保证用的是今天之前的最低价格。

cpp

复制代码
minPrice = min(minPrice, price);        // 先更新最低价
maxProfit = max(maxProfit, price - minPrice);  // 再算利润

如果反过来,可能会用当天的价格买入和卖出,利润为 0,逻辑不对。

  1. 和「买卖股票的最佳时机 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];
    }
};

空间优化:

cpp 复制代码
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)
相关推荐
Shaoshing3 小时前
LeetCode100 42.接雨水
java·算法·leetcode
文丑颜不良啊4 小时前
LeetCode1261~1280题目解析
java·leetcode
qq_466302454 小时前
如何通过部分文件名,读取出整个文件名
c++·qt
not coder4 小时前
一文讲通--从树到红黑树
数据结构·算法
octopus_c4 小时前
C++ 入门
开发语言·c++·算法
爱吃香菜的初学者4 小时前
八.数据结构——哈希表(1)
数据结构·散列表
ZhengEnCi4 小时前
2026年10月30日AI早报:Gemini 4 Carbon登顶、DeepSeek融资1055亿、智元机器人上岗实测
人工智能·算法
强哥聊算力5 小时前
《算力江湖·Intel帝国往事》第三集:安迪·格鲁夫的铁血时代:Intel为什么能把对手逼到墙角?
运维·人工智能·科技·算法·ai·gpu算力
Shaoshing5 小时前
LeetCode100 11. 盛最多水的容器
算法·leetcode
raindayinrain5 小时前
c++新特性--实用新特性
c++