力扣 121 买卖股票最佳时机贪心策略详解

70 阅读3分钟

力扣 121 买卖股票最佳时机贪心策略详解

目录

[TOC]

题目描述

给定一个数组 prices ,其中 prices[i] 表示某股票第 i 天的价格。你只能选择 某一天 买入,并在 未来的某一不同日子 卖出。请计算这笔交易的最大利润。若不能获取利润,返回 0

示例:

输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(价格 = 1)买入,第 5 天(价格 = 6)卖出,利润 = 6-1 = 5。

解题思路

核心思想:贪心策略

我们需要找到最低价买入,并在之后的最高价卖出。但如何高效实现这一点?

  • 关键观察 :假设在第 i 天卖出,则买入价一定是前 i 天中的最低价。

  • 贪心策略 :遍历数组时,维护一个历史最低价 minPrice ,并计算每天卖出时的利润,更新最大利润。


代码实现

/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function (prices) {
  let maxProfit = 0; // 最大利润
  let minPrice = prices[0]; // 最小价格
  for (let i = 1; i < prices.length; i++) {
    // 如果当前价格小于最小价格,则更新最小价格
    if (prices[i] < minPrice) {
      minPrice = prices[i];
    }
    // 如果当前价格大于最小价格,则计算利润 (当前价格 - 最小价格)
    maxProfit = Math.max(maxProfit, prices[i] - minPrice);
  }
  return maxProfit;
};
 
console.log(maxProfit([7, 1, 5, 3, 6, 4]));

算法解析

步骤拆解
  1. 初始化
  • maxProfit = 0 :初始最大利润为0(确保无盈利时返回0)。

  • minPrice = prices[0] :初始最低价为第1天的价格。

  1. 遍历数组
  • 从第2天开始,依次比较每一天的价格。

  • 更新最低价 :如果当前价格比 minPrice 低,则更新 minPrice

  • 计算利润 :如果当前价格高于 minPrice ,则计算当前卖出利润,并与 maxProfit 比较,取较大值。

示例演示

以输入 [7,1,5,3,6,4] 为例:

天数价格minPrice当前利润maxProfit
17700
21100
35144
43124
56155
64135

最终最大利润为 5


正确性证明

  1. 最优子结构
  • 最大利润必然产生于某个最低价之后的高价。

  • 维护 minPrice 确保能捕捉到所有可能的买入点。

  1. 遍历覆盖所有可能性
  • 每一天都尝试以当日价格卖出,并基于历史最低价计算利润,因此不会遗漏最优解。


复杂度分析

  • 时间复杂度 :O(n),仅需一次遍历。

  • 空间复杂度 :O(1),仅用常数变量存储状态。


边界情况处理

  1. 价格递减数组 :如 [7,6,5,4,3] ,最大利润为0。

  2. 单一价格数组 :如 [5,5,5] ,利润为0。

  3. 数组长度为1 :无法交易,直接返回0。


其他解法对比

暴力法(不可取)
  • 思路 :双重循环遍历所有买入卖出组合,计算最大利润。

  • 缺点 :时间复杂度 O(n²),在数据量大时超时。

动态规划
  • 思路 :定义状态 dp[i] 表示前 i 天的最大利润。

  • 状态转移dp[i] = max(dp[i-1], prices[i] - minPrice)

  • 分析 :本质上与贪心策略一致,但贪心法无需额外空间。


总结

贪心策略通过维护历史最低价,将问题转化为一次遍历,高效解决了一次交易的最大利润问题。
关键点

  1. 理解最低价对后续利润的决定性作用。

  2. 遍历过程中不断更新最低价和最大利润。

此方法简洁高效,是同类问题中的经典解法。对于多次交易的问题(如LeetCode 122题),需采用不同的策略。