LeetCode 力扣题目:买卖股票的最佳时机 III

简介: LeetCode 力扣题目:买卖股票的最佳时机 III

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容,和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣!

期待与您一起探索技术、持续学习、一步步打怪升级 欢迎订阅本专栏❤️❤️

题目描述

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。

注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例:

输入: [3,3,5,0,0,3,1,4]

输出: 6

解释: 在第 4 天(股价 = 0)的时候买入,在第 6 天(股价 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3。

随后,在第 7 天(股价 = 1)的时候买入,在第 8 天(股价 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3。

方法一:动态规划

解题步骤

  1. 定义状态:dp[i][j] 表示第 i 天完成 j 笔交易的最大利润。
  2. 初始化状态:dp[0][1]dp[0][2] 都初始化为负无穷,表示不可能完成交易。
  3. 状态转移:
  • i 天完成一笔交易的最大利润:dp[i][1] = max(dp[i-1][1], -prices[i])
  • i 天完成两笔交易的最大利润:dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i])
  1. 结果输出:max(dp[n-1][1], dp[n-1][2])

Python 示例

def maxProfit(prices):
    n = len(prices)
    if n == 0:
        return 0
    dp = [[0] * 3 for _ in range(n)]
    dp[0][1] = -prices[0]
    dp[0][2] = float('-inf')
    
    for i in range(1, n):
        dp[i][1] = max(dp[i-1][1], -prices[i])
        dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i])
    return max(0, dp[n-1][2])
# Example usage
prices = [3,3,5,0,0,3,1,4]
print(maxProfit(prices))  # Output: 6

算法分析

  • 时间复杂度:O(N),其中 N 是数组的长度。
  • 空间复杂度:O(N),用于存储 dp 数组。

算法图解与说明

初始: dp = [[-3, -inf], [0, 0], [0, 0], ...]
第一天: 不操作,买入 -3
第二天: 不操作,维持 -3
第三天: 不操作,维持 -3
第四天: 不操作,买入 0
第五天: 不操作,维持 0
第六天: 卖出 +3
第七天: 买入 1
第八天: 卖出 +4

方法二:状态机优化

解题步骤

  1. 使用四个变量表示不同状态下的最大利润:buy1, sell1, buy2, sell2
  2. 初始状态设为:buy1 = buy2 = -inf, sell1 = sell2 = 0
  3. 更新状态机:
  • buy1: 第一次买入的最大利润
  • sell1: 第一次卖出的最大利润
  • buy2: 第二次买入的最大利润
  • sell2: 第二次卖出的最大利润

Python 示例

def maxProfit(prices):
    buy1, sell1, buy2, sell2 = float('-inf'), 0, float('-inf'), 0
    for price in prices:
        buy1 = max(buy1, -price)
        sell1 = max(sell1, buy1 + price)
        buy2 = max(buy2, sell1 - price)
        sell2 = max(sell2, buy2 + price)
    return sell2
# Example usage
prices = [3,3,5,0,0,3,1,4]
print(maxProfit(prices))  # Output: 6

算法分析

  • 时间复杂度:O(N)
  • 空间复杂度:O(1)

算法图解与说明

状态更新过程:
初始: buy1 = -inf, sell1 = 0, buy2 = -inf, sell2 = 0
价格迭代: 3 -> buy1 = -3
          3 -> sell1 = 0
          5 -> sell1 = 2
          0 -> buy2 = 2
          0 -> 维持
          3 -> sell2 = 5
          1 -> 维持
          4 -> sell2 = 6

这两种方法为买卖股票问题的高级解法,适用于有多次交易机会的场景。

方法三:左右扫描数组法

解题步骤

  1. 使用两个数组 left_profitsright_profitsleft_profits[i] 存储从第一天到第 i 天的最大利润,right_profits[i] 存储从第 i 天到最后一天的最大利润。
  2. 从左到右遍历一遍股价数组,更新 left_profits 为到当前日为止的最大利润。
  3. 从右到左遍历股价数组,更新 right_profits 为从当前日到结束的最大利润。
  4. 最终结果为某一天两边利润之和的最大值。

Python 示例

def maxProfit(prices):
    n = len(prices)
    if n <= 1:
        return 0
    
    left_profits = [0] * n
    right_profits = [0] * n
    
    # 左侧最小值初始化
    min_price = prices[0]
    for i in range(1, n):
        left_profits[i] = max(left_profits[i-1], prices[i] - min_price)
        min_price = min(min_price, prices[i])
    
    # 右侧最大值初始化
    max_price = prices[n-1]
    for i in range(n-2, -1, -1):
        right_profits[i] = max(right_profits[i+1], max_price - prices[i])
        max_price = max(max_price, prices[i])
    
    # 计算两边利润的最大和
    max_profit = 0
    for i in range(n):
        max_profit = max(max_profit, left_profits[i] + right_profits[i])
    
    return max_profit
# Example usage
prices = [3,3,5,0,0,3,1,4]
print(maxProfit(prices))  # Output: 6

算法分析

  • 时间复杂度:O(N),其中 N 是数组的长度。
  • 空间复杂度:O(N),需要两个长度为 N 的数组来存储左右两侧的最大利润。

算法图解与说明

股票价格:  [3, 3, 5, 0, 0, 3, 1, 4]
左侧利润:  [0, 0, 2, 2, 2, 2, 2, 2]
右侧利润:  [3, 3, 3, 3, 3, 3, 3, 0]
最大利润:  每天两侧利润之和的最大值为 6 (第 6 天)

方法四:改进的状态机方法

解题步骤

  1. 减少状态机方法中变量的使用,只使用两个变量跟踪到目前为止的最大利润。
  2. 遍历价格数组时,更新四个关键状态:第一次买入、第一次卖出、第二次买入和第二次卖出的最大利润。
  3. 通过逐步更新这四个状态来最大化最终的利润。

Python 示例

def maxProfit(prices):
    first_buy, first_sell = float('-inf'), 0
    second_buy, second_sell = float('-inf'), 0
    for price in prices:
        first_buy = max(first_buy, -price)
        first_sell = max(first_sell, first_buy + price)
        second_buy = max(second_buy, first_sell - price)
        second_sell = max(second_sell, second_buy + price)
    return second_sell
# Example usage
prices = [3,3,5,0,0,3,1,4]
print(maxProfit(prices))  # Output: 6

算法分析

  • 时间复杂度:O(N),N 是股票价格数组的长度。
  • 空间复杂度:O(1),使用常数空间。

算法图解与说明

初始状态: first_buy = -inf, first_sell = 0, second_buy = -inf, second_sell = 0
更新过程:
- 第1天: first_buy 更新为 -3
- 第2天: 无变化
- 第3天: first_sell 更新为 2
- 第4天: second_buy 更新为 2
- 第5天: 无变化
- 第6天: second_sell 更新为 5
- 第7天: 无变化
- 第8天: second_sell 更新为 6

以上四种方法各有优势,适用于不同的场景和优化需求。可以根据具体需要选择最合适的解决方案。

🌹🌹如果觉得这篇文对你有帮助的话,记得一键三连关注、赞👍🏻、收藏是对作者最大的鼓励,非常感谢 ❥(^_-)

❤️❤️作者知识有限,如有错误,请各位大佬评论区批评指正,不胜感激❥(^_-)

欢迎关注微信公众号 数据分析螺丝钉

相关文章
|
2月前
|
程序员 C语言
【C语言】LeetCode(力扣)上经典题目
【C语言】LeetCode(力扣)上经典题目
|
2月前
|
索引
力扣(LeetCode)数据结构练习题(3)------链表
力扣(LeetCode)数据结构练习题(3)------链表
95 0
|
2月前
力扣(LeetCode)数据结构练习题(2)
力扣(LeetCode)数据结构练习题(2)
31 0
|
2月前
|
存储
力扣(LeetCode)数据结构练习题
力扣(LeetCode)数据结构练习题
56 0
|
4月前
|
算法
leetcode188 买卖股票的最佳时机IV
leetcode188 买卖股票的最佳时机IV
66 0
|
3月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
63 6
|
4月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
124 2
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
43 1
|
3月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口