Skip to content

买卖股票的最佳时机

LeetCode 官方题目链接

题目描述

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0

示例 1:

text
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:

text
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

思路拆解

这道题的核心在于找到一个最低的买入点,以及在这个买入点之后的最高的卖出点。

1. 暴力法(超时)

最简单的想法是两层循环,枚举所有可能的买入和卖出日期,计算利润并取最大值。时间复杂度是 $O(n^2)$,在数据量较大时会超时。

2. 贪心算法(一次遍历)

我们实际上只需要遍历一次数组:

  • 假设我们在第 i 天卖出,那么为了利润最大,我们应该在第 i 天之前的最低价格买入。
  • 我们维护一个变量 minPrice,表示截止到当前位置的最低股票价格。
  • 遍历数组:
    • 如果当前价格比 minPrice 低,更新 minPrice
    • 如果当前价格比 minPrice 高,计算当前卖出的利润 currentPrice - minPrice,并尝试更新全局最大利润 maxProfit

这样,我们只需要遍历一次数组即可得到结果。

代码实现

javascript
/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
    let minPrice = Infinity; // 记录历史最低价
    let maxProfit = 0;       // 记录最大利润

    for (const price of prices) {
        if (price < minPrice) {
            // 发现更低的价格,更新买入点
            minPrice = price;
        } else if (price - minPrice > maxProfit) {
            // 当前价格卖出能获得更高利润,更新最大利润
            maxProfit = price - minPrice;
        }
    }

    return maxProfit;
};

运行演示

假设输入 prices = [7, 1, 5, 3, 6, 4]

  1. price = 7: minPrice 更新为 7, maxProfit = 0
  2. price = 1: minPrice 更新为 1 (比7小), maxProfit = 0
  3. price = 5: 5 - 1 = 4, maxProfit 更新为 4
  4. price = 3: 3 - 1 = 2, 小于 4, 不更新
  5. price = 6: 6 - 1 = 5, maxProfit 更新为 5
  6. price = 4: 4 - 1 = 3, 小于 5, 不更新

最终返回 5

复杂度分析

  • 时间复杂度:$O(n)$,只需要遍历一次数组。
  • 空间复杂度:$O(1)$,只使用了常数个变量。

Power by VitePress