LeetCode 121.买卖股票的最佳时机(Python)

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

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

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

示例 1:

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

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

提示:

1 <= prices.length <= 105 0 <= prices[i] <= 104

方法一:记录最低价格法(贪心算法)

这种方法的基本思路是在遍历股票价格的过程中,始终记录遇到的最低买入价格,然后计算当前价格卖出所能获得的利润,并不断更新最大利润。

具体步骤
1. 初始化
• 将 min_price 设为一个非常大的值(或数组的第一个价格)。
• 将 max_profit 初始化为 0。
2. 遍历数组
• 对于数组中的每个价格:
• 如果当前价格小于 min_price,则更新 min_price。
• 否则计算当前价格与 min_price 的差值(即利润),并更新 max_profit(如果该利润更高)。
3. 返回结果
• 遍历结束后,max_profit 即为所能获得的最大利润。

def max_profit(prices):
    # 初始化最低价格和最大利润
    min_price = float('inf')
    max_profit = 0
    
    # 遍历每一天的价格
    for price in prices:
        # 如果当前价格低于之前的最低价格,更新最低价格
        if price < min_price:
            min_price = price
        else:
            # 否则计算卖出利润,并更新最大利润
            profit = price - min_price
            if profit > max_profit:
                max_profit = profit
    return max_profit

详细解析
示例 1: 对于 [7, 1, 5, 3, 6, 4]:
• 第一天价格 7,min_price = 7。
• 第二天价格 1,更新 min_price = 1。
• 第三天价格 5,利润为 5 - 1 = 4,更新 max_profit = 4。
• 第四天价格 3,利润为 3 - 1 = 2,max_profit 保持不变。
• 第五天价格 6,利润为 6 - 1 = 5,更新 max_profit = 5。
• 第六天价格 4,利润为 4 - 1 = 3,max_profit 保持不变。
最终返回 5。
示例 2: 对于 [7, 6, 4, 3, 1]:
每天价格均低于前一天,所以没有任何买卖能产生正利润,最终返回 0。

这种方法的时间复杂度是 O(n),空间复杂度是 O(1)。


2.动态规划方法

动态规划的方法将问题转换为在每一天 持有股票不持有股票 两种状态的转移问题。

定义状态

  • dp[i][0]:表示第 ( i ) 天结束时 不持有股票 的最大利润。
  • dp[i][1]:表示第 ( i ) 天结束时 持有股票 的最大利润。

由于题目只允许进行一次交易,状态转移如下:
不持有股票状态
dp[i][0] = max(dp[i-1][0], dp[i-1][1] +prices[i])
其中,dp[i-1][1] + prices[i] 表示 今天卖出股票 的利润。
持有股票状态
dp[i][1] = max(dp[i-1][1], -prices[i])
其中,-prices[i] 表示在第 ( i ) 天 买入股票 的操作(只允许买入一次)。

def max_profit_dp(prices):
    if not prices:
        return 0
    
    n = len(prices)
    # 初始状态:第 0 天不持有股票利润为 0,第 0 天持有股票利润为 -prices[0]
    dp0 = 0          
    dp1 = -prices[0] 
    
    for i in range(1, n):
        # 更新不持有股票的状态:可以选择继续保持,也可以选择今天卖出
        dp0 = max(dp0, dp1 + prices[i])
        # 更新持有股票的状态:选择继续持有,或者在今天买入(因为只允许买入一次,所以直接取 -prices[i])
        dp1 = max(dp1, -prices[i])
    
    return dp0

3.暴力枚举法

暴力枚举法的思路是遍历所有可能的买入和卖出组合,计算每种组合的利润,并取其中的最大值。
由于需要嵌套遍历所有买卖对,这种方法的时间复杂度为 O(n^2),在数据量较大时效率较低。

def max_profit_brute_force(prices):
    n = len(prices)
    max_profit = 0
    for i in range(n):
        for j in range(i+1, n):
            profit = prices[j] - prices[i]
            if profit > max_profit:
                max_profit = profit
    return max_profit


总结
记录最低价格法(贪心算法):
• 时间复杂度:O(n)
• 空间复杂度:O(1)
• 思路:遍历过程中记录最低买入价,计算并更新最大利润。
动态规划法
• 同样可以在 O(n) 时间内求解。
• 思路:将问题转化为状态转移问题(持有和不持有股票两种状态)。
暴力枚举法:
• 时间复杂度:O(n^2)
• 虽然直观易懂,但效率较低,适合数据规模较小的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值