买卖股票的最佳时机 题解

买卖股票的最佳时机

问题描述

给定一个数组 prices,其中 prices[i] 表示第 i 天的股票价格。你只能选择某一天买入股票,并选择未来的某一天卖出股票,设计一个算法来计算你所能获取的最大利润。

  • 限制条件

    • 只能进行一次交易:也就是说,最多只能买入和卖出各一次。
    • 买入必须在卖出之前:不能在买入之前卖出股票。
  • 目标:返回可以获得的最大利润。如果无法获取任何利润,返回 0

示例
  • 示例 1

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

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

为了求最大利润,我们需要在买入价格最低的时候买入,并在之后价格最高的时候卖出。然而,由于我们只能遍历一次数组,并且需要在买入之后才能卖出,因此我们需要一种高效的方法来计算最大利润。

核心思想

  • 维护一个当前为止的最低买入价格 minPrice
  • 计算当前价格与最低买入价格之间的差值,即当前可获得的利润 price - minPrice
  • 维护一个最大利润值 maxProfit,在遍历过程中更新它。
算法步骤
  1. 初始化

    • minPrice = Infinity:表示当前遇到的最低价格,初始为正无穷大。
    • maxProfit = 0:表示当前计算的最大利润,初始为 0。
  2. 遍历价格数组

    对于每个价格 price,执行以下操作:

    • 更新最低价格

      • 如果 price < minPrice,则更新 minPrice = price
    • 计算当前利润并更新最大利润

      • 计算当前利润 profit = price - minPrice
      • 如果 profit > maxProfit,则更新 maxProfit = profit
  3. 返回结果

    • 遍历完成后,maxProfit 即为所能获得的最大利润。
代码详解
function maxProfit(prices: number[]): number {
    let minPrice = Infinity; // 初始化最低价格为无穷大
    let maxProfit = 0;       // 初始化最大利润为 0

    for (let price of prices) {
        if (price < minPrice) {
            minPrice = price; // 更新最低价格
        } else if (price - minPrice > maxProfit) {
            maxProfit = price - minPrice; // 更新最大利润
        }
    }

    return maxProfit;
}
  • 变量初始化

    • minPrice:用于记录当前为止的最低买入价格。
    • maxProfit:用于记录当前为止的最大利润。
  • 遍历数组

    for (let price of prices) {
        ...
    }
    
    • 更新最低价格

      if (price < minPrice) {
          minPrice = price;
      }
      
      • 如果当前价格比之前记录的最低价格还低,更新最低价格。
    • 更新最大利润

      else if (price - minPrice > maxProfit) {
          maxProfit = price - minPrice;
      }
      
      • 如果当前价格与最低价格的差值(利润)大于之前的最大利润,更新最大利润。
  • 返回结果

    return maxProfit;
    
    • 返回计算得到的最大利润。
示例演示

以示例 1 为例,prices = [7,1,5,3,6,4]

  • 初始状态

    • minPrice = Infinity
    • maxProfit = 0
  • 遍历过程

    1. price = 7

      • 7 < Infinity,更新 minPrice = 7
      • 没有更新 maxProfit,因为 price - minPrice = 0
    2. price = 1

      • 1 < 7,更新 minPrice = 1
      • 没有更新 maxProfit,因为 price - minPrice = 0
    3. price = 5

      • 5 > 1,计算利润 5 - 1 = 4
      • 4 > 0,更新 maxProfit = 4
    4. price = 3

      • 3 > 1,计算利润 3 - 1 = 2
      • 2 < 4maxProfit 不变。
    5. price = 6

      • 6 > 1,计算利润 6 - 1 = 5
      • 5 > 4,更新 maxProfit = 5
    6. price = 4

      • 4 > 1,计算利润 4 - 1 = 3
      • 3 < 5maxProfit 不变。
  • 结果

    • 最终 maxProfit = 5
时间和空间复杂度分析
  • 时间复杂度:O(n),其中 n 是数组 prices 的长度。我们只需要遍历一次数组。

  • 空间复杂度:O(1),只使用了常数级别的额外空间。

边界情况处理
  • 价格单调递减

    • 例如 prices = [7,6,4,3,1],在这种情况下,无法获得正利润。
    • 算法会始终更新 minPrice,但 maxProfit 保持为 0。
    • 最终返回 0。
  • 只有一个价格

    • prices.length == 1 时,无法完成交易,利润为 0。
测试代码
function testMaxProfit() {
    const testCases = [
        { prices: [7, 1, 5, 3, 6, 4], expected: 5 },
        { prices: [7, 6, 4, 3, 1], expected: 0 },
        { prices: [1, 2], expected: 1 },
        { prices: [2, 4, 1], expected: 2 },
        { prices: [3], expected: 0 },
    ];

    for (let { prices, expected } of testCases) {
        const result = maxProfit(prices);
        console.assert(result === expected, `测试失败:输入 ${prices},期望输出 ${expected},实际输出 ${result}`);
    }

    console.log("所有测试用例通过!");
}

testMaxProfit();
总结
  • 核心思想:在一次遍历中,找到最低的买入价格和最高的卖出价格(在买入之后)。
  • 算法优势:时间复杂度低,只需要遍历一次数组,空间复杂度为 O(1)。
  • 注意事项:在更新 minPrice 时,只更新更低的价格;在计算利润时,必须确保当前价格是在 minPrice 之后的。
## 软件功能详细介绍 1. **文本片段管理**:可以添加、编辑、删除常用文本片段,方便快速调用 2. **分组管理**:支持创建多个分组,不同类型的文本片段可以分类存储 3. **热键绑定**:为每个文本片段绑定自定义热键,实现一键粘贴 4. **窗口置顶**:支持窗口置顶功能,方便在其他应用程序上直接使用 5. **自动隐藏**:可以设置自动隐藏,减少桌面占用空间 6. **数据持久化**:所有配置和文本片段会自动保存,下次启动时自动加载 ## 软件使用技巧说明 1. **快速添加文本**:在文本输入框中输入内容后,点击"添加内容"按钮即可快速添加 2. **批量管理**:可以同时编辑多个文本片段,提高管理效率 3. **热键冲突处理**:如果设置的热键与系统或其他软件冲突,会自动提示 4. **分组切换**:使用分组按钮可以快速切换不同类别的文本片段 5. **文本格式化**:支持在文本片段中使用换行符和制表符等格式 ## 软件操作方法指南 1. **启动软件**:双击"大飞哥软件自习室——快捷粘贴工具.exe"文件即可启动 2. **添加文本片段**: - 在主界面的文本输入框中输入要保存的内容 - 点击"添加内容"按钮 - 在弹出的对话框中设置热键和分组 - 点击"确定"保存 3. **使用热键粘贴**: - 确保软件处于运行状态 - 在需要粘贴的位置按下设置的热键 - 文本片段会自动粘贴到当前位置 4. **编辑文本片段**: - 选中要编辑的文本片段 - 点击"编辑"按钮 - 修改内容或热键设置 - 点击"确定"保存修改 5. **删除文本片段**: - 选中要删除的文本片段 - 点击"删除"按钮 - 在确认对话框中点击"确定"即可删除
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小李学软件

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值