【LeetCode】动态规划—123. 买卖股票的最佳时机 III(附完整Python/C++代码)

news2024/11/22 13:38:18

动态规划—123. 买卖股票的最佳时机 III

  • 题目描述
  • 前言
  • 基本思路
    • 1. 问题定义
    • 2. 理解问题和递推关系
      • 状态定义:
      • 状态转移公式:
      • 初始条件:
    • 3. 解决方法
      • 动态规划方法
      • 伪代码:
    • 4. 进一步优化
    • 5. 小总结
  • Python代码
      • Python代码解释
  • C++代码
      • C++代码解释
  • 总结

题目描述

在这里插入图片描述

前言

买卖股票的最佳时机 III 是一个动态规划问题的经典变种。给定一个数组 prices,其中 prices[i] 代表第 i 天的股票价格。你最多可以进行 两次交易(一次交易包含一次买入和一次卖出),目标是通过这两次交易获得最大的利润。该问题的难点在于如何合理规划买卖时机,以获取最大收益。


基本思路

1. 问题定义

给定一个数组 prices,其中 prices[i] 表示股票第 i 天的价格。你最多可以进行两次交易,求这两次交易所能获取的最大利润。注意:两次交易不能交叉进行(必须卖掉一次股票才能再次买入)。

2. 理解问题和递推关系

为了解决该问题,我们可以将其拆解为两个阶段:

  1. 第一次交易:在某天买入并在稍后的一天卖出,获取第一次交易的最大利润。
  2. 第二次交易:在某天(第一次交易之后)再次买入股票并卖出,获取第二次交易的最大利润。

状态定义:

我们可以定义 4 个状态:

  1. first_buy[i]:表示在第 i 天结束时,我们第一次买入股票时的最大收益。
  2. first_sell[i]:表示在第 i 天结束时,我们第一次卖出股票时的最大收益。
  3. second_buy[i]:表示在第 i 天结束时,我们第二次买入股票时的最大收益。
  4. second_sell[i]:表示在第 i 天结束时,我们第二次卖出股票时的最大收益。

状态转移公式:

  1. 第一次买入的状态转移
    f i r s t _ b u y [ i ] = max ⁡ ( f i r s t _ b u y [ i − 1 ] , − p r i c e s [ i ] ) first\_buy[i] = \max(first\_buy[i-1], -prices[i]) first_buy[i]=max(first_buy[i1],prices[i])

    • 要么我们保持之前的状态不变,继续持有第一次买入的股票;
    • 要么在第 i 天以当前价格 prices[i] 买入股票。
  2. 第一次卖出的状态转移
    f i r s t _ s e l l [ i ] = max ⁡ ( f i r s t _ s e l l [ i − 1 ] , f i r s t _ b u y [ i − 1 ] + p r i c e s [ i ] ) first\_sell[i] = \max(first\_sell[i-1], first\_buy[i-1] + prices[i]) first_sell[i]=max(first_sell[i1],first_buy[i1]+prices[i])

    • 要么我们保持之前的状态不变,继续持有卖出后的最大利润;
    • 要么在第 i 天卖出股票,利润为 first_buy[i-1] + prices[i]
  3. 第二次买入的状态转移
    s e c o n d _ b u y [ i ] = max ⁡ ( s e c o n d _ b u y [ i − 1 ] , f i r s t _ s e l l [ i − 1 ] − p r i c e s [ i ] ) second\_buy[i] = \max(second\_buy[i-1], first\_sell[i-1] - prices[i]) second_buy[i]=max(second_buy[i1],first_sell[i1]prices[i])

    • 要么我们保持之前的状态不变,继续持有第二次买入的股票;
    • 要么在第 i 天买入股票,利润为 first_sell[i-1] - prices[i]
  4. 第二次卖出的状态转移
    s e c o n d _ s e l l [ i ] = max ⁡ ( s e c o n d _ s e l l [ i − 1 ] , s e c o n d _ b u y [ i − 1 ] + p r i c e s [ i ] ) second\_sell[i] = \max(second\_sell[i-1], second\_buy[i-1] + prices[i]) second_sell[i]=max(second_sell[i1],second_buy[i1]+prices[i])

    • 要么我们保持之前的状态不变,继续持有第二次卖出的最大利润;
    • 要么在第 i 天卖出股票,利润为 second_buy[i-1] + prices[i]

初始条件:

  • first_buy[0] = -prices[0],第一次买入的初始状态。
  • first_sell[0] = 0,第一次卖出的初始状态。
  • second_buy[0] = -prices[0],第二次买入的初始状态。
  • second_sell[0] = 0,第二次卖出的初始状态。

3. 解决方法

动态规划方法

  1. 定义 4 个状态 first_buy[i]first_sell[i]second_buy[i]second_sell[i] 表示在第 i 天结束时的最大收益。
  2. 通过递推公式更新这些状态。
  3. 最终结果为 second_sell[n-1],即最多进行两次交易后在最后一天的最大利润。

伪代码:

initialize first_buy = -prices[0], first_sell = 0, second_buy = -prices[0], second_sell = 0
for i from 1 to n-1:
    first_buy = max(first_buy, -prices[i])
    first_sell = max(first_sell, first_buy + prices[i])
    second_buy = max(second_buy, first_sell - prices[i])
    second_sell = max(second_sell, second_buy + prices[i])
return second_sell

4. 进一步优化

  • 空间优化:由于每个状态只依赖于前一天的状态,我们可以将动态规划的 4 个状态用常量来代替,优化空间复杂度为 O(1)

5. 小总结

  • 问题思路:通过定义四个状态,分别对应两次买入和卖出的最大利润,使用动态规划可以有效求解。
  • 时间复杂度:该方法的时间复杂度为 O(n),空间复杂度可以优化为 O(1)

以上就是买卖股票的最佳时机 III问题的基本思路。


Python代码

class Solution:
    def maxProfit(self, prices: list[int]) -> int:
        if not prices:
            return 0

        # 初始化四个状态
        first_buy = second_buy = -prices[0]
        first_sell = second_sell = 0

        for i in range(1, len(prices)):
            # 依次更新四个状态
            first_buy = max(first_buy, -prices[i])
            first_sell = max(first_sell, first_buy + prices[i])
            second_buy = max(second_buy, first_sell - prices[i])
            second_sell = max(second_sell, second_buy + prices[i])

        # 返回最终状态的最大值
        return second_sell

Python代码解释

  1. 初始化first_buysecond_buy 初始为 -prices[0]first_sellsecond_sell 初始为 0
  2. 状态转移:通过递推公式依次更新四个状态。
  3. 返回结果:最终返回 second_sell,即最大利润。

C++代码

#include <vector>
#include <algorithm>
using namespace std;

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.empty()) return 0;

        // 初始化四个状态
        int first_buy = -prices[0], first_sell = 0;
        int second_buy = -prices[0], second_sell = 0;

        for (int i = 1; i < prices.size(); ++i) {
            // 依次更新四个状态
            first_buy = max(first_buy, -prices[i]);
            first_sell = max(first_sell, first_buy + prices[i]);
            second_buy = max(second_buy, first_sell - prices[i]);
            second_sell = max(second_sell, second_buy + prices[i]);
        }

        // 返回最终状态的最大值
        return second_sell;
    }
};

C++代码解释

  1. 初始化first_buysecond_buy 初始为 -prices[0]first_sellsecond_sell 初始为 0
  2. 状态转移:通过递推公式依次更新四个状态。
  3. 返回结果:最终返回 second_sell,即最大利润。

总结

  • 核心思路:通过动态规划,定义四个状态来跟踪两次买入和两次卖出的最大利润,并通过状态转移公式逐步更新,最终获取最大利润。
  • 时间复杂度:时间复杂度为 O(n),适合处理大规模数据。
  • 空间优化:由于状态之间只依赖前一天的状态,空间复杂度可以优化为 O(1),这使得算法在空间效率上达到最优。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2209494.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

『网络游戏』代码操作数据库增删改查【22】

创建一个新的Vistual Studio案例工程 命名为SqlTest 导入MySql.dll (官网安装即可) 导入到新建工程创建Libs文件夹放里即可 浏览找到位置添加引用即可 1.增加数据 编写脚本&#xff1a;Program 运行工程 - 添加/插入完成 打开navicat查看数据库表信息 在增加数据中可以获取主…

如何安装Tensorflow GPU版本

可以安装对应版本的cudatoolkit cudnn 我这次需要安装tensorflow-gpu1.15.0 经查看 对应的cuda 10 所以&#xff1a; conda install cudatoolkit10.0.130它对应的是cudnn 7.4 但是没安装成功 然后我直接输入 conda install cudnn 它根据cuda10 找到了对应的cudnn 7.6.…

13.JVM内存模型深度剖析

一、JDK体系结构 JDK代表Java Development Kit(Java开发工具包)&#xff0c;是用于开发和编译Java应用程序的软件包。JDK是由Oracle提供的Java平台的官方实现&#xff0c;包含了开发和运行Java程序所需的工具、库和JRE(Java Runtime Environment)。 二、JAVA语言跨平台特性 Ja…

控制模型执行 | AnyLogic帮助

控制模型执行 | AnyLogic帮助 当运行AnyLogic模型时&#xff0c;您可以使用控制面板来控制模型的执行&#xff0c;控制面板显示在AnyLogic模型窗口的底部。 控制面板包含用于控制启动模型执行的按钮&#xff1a; 按钮命令描述运行[仅当模型当前未运行时可见]从当前状态运行模…

无人机之交互系统篇

一、系统构成 无人机交互系统通常由多个子系统组成&#xff0c;包括但不限于&#xff1a; 多模式人机交互装置&#xff1a;这是人机交互系统的基础层&#xff0c;通常包括计算机、局域网、传感器等设备&#xff0c;用于实现操作员与无人机之间的数据交互和指令传递。例如&…

MATLAB实现AM调制解调

1.基本概念 1.1 AM调制原理 调幅就是使载波的振幅随调制信号的变化规律而变化。基带信号m(t)与直流分量A0相加&#xff0c;然后和高频载波相乘实现AM信号的调制&#xff0c;如图1所示。 1.2 AM解调原理 AM信号经过信道传输&#xff0c;引入噪声后&#xff0c;再和载波相乘&…

jenkins 插件Publish Over SSH (sskey) 同步文件夹

一、安装插件 Publish Over SSH SSH Pipeline Steps 二、添加sshkey 将ssh免密登录的私钥新建到 二、准备目录 源&#xff1a;images 目标&#xff1a;/root/images2 流水线脚本 pipeline {agent anystages {stage(Dest) {steps {script{def remote [:]remote.name tstr…

【中短文--深度学习笔记】Batchsize的选择、批量归一化、loss是否已经收敛(更新中-ing)

一、如何选择合适的Batchsize&#xff1f; 如果你没有任何参考&#xff0c;那么选择2的n次方&#xff08;即64、128、256、512、1024等&#xff09;可以会更加直接和易于管理。而对于上限来说&#xff0c;batchsize大小最好<数据集样本数*0.1。 why? 梯度下降算法 在更新模…

盈利路上的关键一步:掌握五大交易离场技巧

近期&#xff0c;股市节后短暂的牛市成为了众人瞩目的焦点。有人收获颇丰&#xff0c;也有人因此亏了不少&#xff0c;时机没抓对&#xff0c;倒是被割了一波韭菜。市场起伏已是常态&#xff0c;但依旧会有很多人中招。围观近况&#xff0c;忽然深刻体会到&#xff0c;适时离场…

二值形态学基本运算的几何解释

Rafael Gonzalez和Richard Woods所著的《数字图像处理》&#xff0c;从集合角度定义膨胀和腐蚀&#xff0c;不易理解。本书从空域滤波角度对二值图像形态学中膨胀和腐蚀的定义和过程进行描述&#xff0c;并给出了动画演示过程。使用结构元素对图像的形态学处理与滤波模板的空域…

HIVE beeline连接报错Operation category READ is not supported in state standby

问题&#xff1a;hive连接报错Operation category READ is not supported in state standby 这个可能是因为hive配置的hdfs连接地址指定的是具体的namenode地址&#xff0c;但是hadoop集群配置的是HA,所以会发生主备切换&#xff0c;那么我们hive元数据配置就需要使用NameNode…

JavaEE-进程与线程

1.进程 1.1什么是进程 每个应⽤程序运⾏于现代操作系统之上时&#xff0c;操作系统会提供⼀种抽象&#xff0c;好像系统上只有这个程序在运 ⾏&#xff0c;所有的硬件资源都被这个程序在使⽤。这种假象是通过抽象了⼀个进程的概念来完成的&#xff0c;进程可 以说是计算机科学…

Arduino IDE 导入库(DallasTemperature.h和OneWire.h)

1打开IDE 2点击项目 3点击导入库 4在点击管理库 5搜索库 在下图的位置输入库名即可 6安装即可

基于Springboot+Vue的医疗废物管理系统 (含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 在系统…

基于yolov8、yolov5的交通标志检测识别系统(含UI界面、Python代码、数据集)

项目介绍 项目中所用到的算法模型和数据集等信息如下&#xff1a; 算法模型&#xff1a;     yolov8、yolov8 SE注意力机制 或 yolov5、yolov5 SE注意力机制 &#xff0c; 直接提供最少两个训练好的模型。模型十分重要&#xff0c;因为有些同学的电脑没有 GPU&#xff0…

避免 Python 类型转换错误:实用指南

在 Python 中&#xff0c;变量的类型是明确的&#xff0c;不能在没有显式转换的情况下直接将一种类型的值赋给另一种不同类型的变量。例如&#xff0c;以下将字符串与整数直接相加会报错&#xff0c;这跟其它语言有所差异&#xff0c;其它语言会进行隐式转 a "5" b…

c++类与对象三

C类与对象三 上期我们介绍了类的实例化&#xff0c;大小计算&#xff0c;还有this指针。这期我们继续深入更高层次的用法 类的六个默认函数 如个一个类里面没有成员&#xff0c;就是空类&#xff0c;但是空类里面真的什么都没有吗&#xff0c;并不是&#xff0c;在编译器中&…

大数据新视界 --大数据大厂之大数据环境下的零信任安全架构:构建可靠防护体系

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

Javascript 仅允许在异步函数和模块顶级使用 “await“

这个错误的原因&#xff0c;是我们在一个普通函数里调用了async函数&#xff0c;因为async 函数是异步函数&#xff0c;它返回一个 Promis&#xff0c;await必须与async一同出现。所以这里普通函数无法调用它。 async和await只是使函数调用看起来像同步而已&#xff0c;比如下…

【MMMLP】核心方法解读

此方法用于顺序推荐&#xff0c;和我的研究方向不一样&#xff0c;所以这里只探讨值得借鉴的部分 abstract&#xff1a; 现有的顺序推荐方法要么不能直接处理多模态&#xff0c;要么计算量大。为了解决这个问题&#xff0c;我们提出了一种新的多模态多层感知器&#xff08;MM…