在问 · 算法题解

121. 买卖股票的最佳时机

简单贪心维护历史最低价力扣原题 ↗

题目描述

输入数组 prices,prices[i] 是某支股票第 i 天的价格。

你最多只做一次交易:先在某一天买入一股,再在之后的另一天卖出。卖出日必须晚于买入日。

返回能得到的最大利润。如果怎么交易都赚不到钱,就不交易,返回 0。

示例 1
输入:prices = [7,1,5,3,6,4]
输出:5

解释:价格为 1 时买入、为 6 时卖出,利润 5;不能先以 7 卖出再以 1 买入。

示例 2
输入:prices = [7,6,4,3,1]
输出:0

解释:价格一路下跌,不交易,利润为 0。

数据范围

  • 1 <= prices.length <= 10^5
  • 0 <= prices[i] <= 10^4

解题思路:维护历史最低价

扫描价格,维护至今最低买入价,并用当前价减它更新利润。

为什么正确

扫描到当前位置时,best_buy 是此前最便宜的价格,profit 是此前可得最大利润。

复杂度分析

时间 O(n),空间 O(1)。

易错点

先更新最低价再计算差值仍然正确,因为当天买入不会产生正利润;不要允许卖出发生在买入之前。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

from typing import List

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        best_buy = float('inf')
        profit = 0
        for price in prices:
            best_buy = min(best_buy, price)
            profit = max(profit, price - best_buy)
        return profit

载入编辑器,自己跑一遍 →

其他解法

两种解法都是一次扫描、O(1) 空间;维护最低价从买入点角度思考,差分数组把问题归结为最大子段和。

解法 2:差分数组最大子段和 时间 O(n),空间 O(1)

第 i 天买、第 j 天卖的利润,等于相邻两天价差在区间 (i, j] 上的和。问题转化为价差序列的最大子段和。用 Kadane 算法:cur = max(0, cur + 价差),再用 cur 更新答案。

复杂度和主解法相同,但揭示了本题与「53. 最大子数组和」的联系。不如维护最低价直观。

from typing import List

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        cur = 0
        profit = 0
        for i in range(1, len(prices)):
            cur = max(0, cur + prices[i] - prices[i - 1])
            profit = max(profit, cur)
        return profit

贪心 专题的其他题目

查看 贪心 全部题目 →