当前位置: 首页 > news >正文

【LeetCode 热题 100】121. 买卖股票的最佳时机

Problem: 121. 买卖股票的最佳时机
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

文章目录

  • 整体思路
  • 完整代码
  • 时空复杂度
    • 时间复杂度:O(N)
    • 空间复杂度:O(1)

整体思路

这段代码旨在解决一个非常经典的股票交易问题:买卖股票的最佳时机 I (Best Time to Buy and Sell Stock)。问题要求在给定的一系列每日股票价格中,通过一次买入和一次卖出交易,找到能够获得的最大利润。如果无法获利(即价格一直在下跌),则最大利润为0。

该算法采用了一种非常高效的 单次遍历(Single Pass) 贪心策略。其核心思想是在遍历价格数组的过程中,动态地维护两个关键信息:

  1. 历史最低价格 (Historical Minimum Price):记录到当前日期为止,所遇到的股票的最低价格。
  2. 最大利润 (Maximum Profit):记录到当前日期为止,通过在历史最低点买入、在某一天卖出所能实现的最大收益。

算法的具体执行步骤如下:

  1. 初始化

    • 创建一个变量 minPrice,用于存储历史最低价格。它被初始化为第一天的价格 prices[0]
    • 创建一个变量 ans,用于存储最大利润。它被初始化为 0,因为如果没有任何交易可以获利,利润就是0。
  2. 单次遍历

    • 算法通过一个 for 循环,从左到右遍历整个 prices 数组。每一次迭代都可以看作是时间向前推移一天。
    • 在循环的每一天(对应价格 p),算法会执行两个关键操作,且顺序非常重要
      a. 计算潜在利润并更新最大利润:首先,算法假设今天是卖出日。它会计算今天卖出的价格 p之前的历史最低买入价 minPrice 之间的差值,即 p - minPrice。这个差值就是如果在历史最低点买入、在今天卖出所能获得的利润。然后,用这个潜在利润与已记录的最大利润 ans 进行比较,并将 ans 更新为较大者。
      b. 更新历史最低价格:在完成利润计算之后,算法会用今天的价格 p 来更新 minPrice。即比较当前的 minPrice 和今天的 p,并将 minPrice 更新为较小者。这样做是为了给未来的日子提供一个更新后的、可能更低的买入价格。
  3. 返回结果

    • 当遍历完所有价格后,ans 变量中就存储了在整个时间段内进行一次交易所能获得的最大利润。将其返回即可。

这个算法的巧妙之处在于,它通过一次遍历就解决了问题。在每一天,它都利用过去的信息(minPrice)来做当前的最优决策(更新ans),同时更新自身状态(更新minPrice)以供未来使用。

完整代码

class Solution {/*** 计算只进行一次买卖股票交易能获得的最大利润。* @param prices 每日股票价格的数组* @return 最大利润*/public int maxProfit(int[] prices) {// minPrice: 用于记录到目前为止遇到的最低股票价格。// 初始化为第一天的价格,作为比较的起点。int minPrice = prices[0];// ans: 用于存储找到的最大利润。// 初始化为 0,因为如果无法获利,最大利润就是 0。int ans = 0;// 遍历价格数组,p 代表当天的价格for (int p : prices) {// 关键步骤 1: 计算今天卖出能获得的最大利润。// p 是今天的卖出价,minPrice 是在今天之前能买入的最低价。// 用这个潜在的利润去更新全局的最大利润 ans。// 这个操作必须在更新 minPrice 之前,因为不能在同一天买入又卖出。ans = Math.max(ans, p - minPrice);// 关键步骤 2: 更新历史最低价格。// 用今天的价格 p 和已记录的最低价 minPrice 比较,// 并将 minPrice 更新为更小的值,供未来的日子计算利润时使用。minPrice = Math.min(minPrice, p);}// 遍历结束后,ans 中存储的就是整个时间段内的最大利润return ans;}
}

时空复杂度

时间复杂度:O(N)

  1. 循环:算法的核心是一个 for-each 循环,它遍历 prices 数组中的每一个元素一次。如果数组的长度为 N,这个循环将执行 N 次。
  2. 循环内部操作
    • 在循环的每一次迭代中,只执行了两次 Math.max/Math.min 操作和一次减法操作。
    • 这些操作都是基本运算,其时间复杂度为 O(1)

综合分析
算法由 N 次 O(1) 的操作组成。因此,总的时间复杂度是 N * O(1) = O(N)

空间复杂度:O(1)

  1. 主要存储开销:算法只使用了几个固定数量的整型变量(minPrice, ans, p)。
  2. 空间大小:这些变量的数量不随输入数组 prices 的大小 N 而改变。

综合分析
算法没有使用任何与输入规模 N 成比例的额外数据结构(如新数组或哈希表)。因此,其额外辅助空间复杂度为 O(1)

参考灵神

http://www.lryc.cn/news/622396.html

相关文章:

  • OpenZeppelin Contracts 架构分层分析
  • 再回C的进制转换--负数
  • python的美食交流社区系统
  • 【Spring Cloud 微服务】1.Hystrix断路器
  • 两幅美国国旗版权挂钩专利发起跨境诉讼
  • 列式存储与行式存储:核心区别、优缺点及代表数据库
  • Spring Boot 静态函数无法自动注入 Bean?深入解析与解决方案
  • 上下文块嵌入(contextualized-chunk-embeddings)
  • Mybatis简单练习注解sql和配置文件sql+注解形式加载+配置文件加载
  • 图像识别控制技术(Sikuli)深度解析:原理、应用与商业化前景
  • System V通信机制
  • Web攻防-大模型应用LLM安全提示词注入不安全输出代码注入直接间接数据投毒
  • Go语言 time 包详解:从基础到实战
  • Vue模板引用(Template Refs)全解析1
  • 介绍大根堆小根堆
  • 命令模式C++
  • 【DSP28335 事件驱动】唤醒沉睡的 CPU:外部中断 (XINT) 实战
  • AI - MCP 协议(一)
  • 备忘录模式C++
  • 线性代数 · 直观理解矩阵 | 空间变换 / 特征值 / 特征向量
  • JavaScript递归
  • nVidia Tesla P40使用anaconda本地重编译pytorch3d成功加载ComfyUI-3D-Pack
  • 磁悬浮轴承“幽灵振动”克星:深度解析同频振动机理与精准打击策略
  • 日常反思总结
  • Layui 语法详解与全功能示例
  • GoLand深度解析:智能开发利器与cpolar内网穿透的协同革命
  • 基于Spring Boot的智能民宿预订与游玩系统设计与实现 民宿管理系统 民宿预订系统 民宿订房系统
  • Linux操作系统从入门到实战(二十二)命令行参数与环境变量
  • Lecture 10: Concurrency 3
  • 【嵌入式硬件实例】-555定时器驱动直流无刷电机