代码随想录训练营 Day41打卡 动态规划 part08 121. 买卖股票的最佳时机 122. 买卖股票的最佳时机II 123. 买卖股票的最佳时机III

news2024/12/23 17:40:39

代码随想录训练营 Day41打卡 动态规划 part08

一、力扣121. 买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
示例
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

在这个问题中,我们需要计算在给定的股票价格数组 prices 中,最多只能进行一次交易(即一次买入和一次卖出)的情况下,能够获得的最大利润。为了实现这一点,我们使用动态规划的方法来模拟整个买卖过程。

我们定义两个状态:

  • dp[i][0] 表示第 i 天持有股票时能够获得的最大现金金额。
  • dp[i][1] 表示第 i 天不持有股票时能够获得的最大现金金额。

注意,“持有股票”不一定表示当天买入股票,也可能是之前买入的,并且持续持有到当天。同样地,“不持有股票”可以是当天卖出股票,或者之前已经卖出并且保持不持有状态。

持有股票时 (dp[i][0]):

如果第 i-1 天已经持有股票,那么保持现状:dp[i - 1][0]。
如果第 i 天买入股票,那么所得现金为 -prices[i]。
公式:dp[i][0] = max(dp[i - 1][0], -prices[i])

不持有股票时 (dp[i][1]):

如果第 i-1 天已经不持有股票,那么保持现状:dp[i - 1][1]。
如果第 i 天卖出股票,那么所得现金为 prices[i] + dp[i - 1][0]。
公式:dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0])
以示例输入:[7,1,5,3,6,4]为例,dp数组状态如下:
在这里插入图片描述
dp[5][1]就是最终结果。

为什么不是dp[5][0]呢?

因为本题中不持有股票状态所得金钱一定比持有股票状态得到的多!

代码实现

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        length = len(prices)
        if length == 0:
            return 0
        
        # 初始化 dp 数组,大小为 [length][2]
        # dp[i][0] 表示第 i 天持有股票时的最大现金
        # dp[i][1] 表示第 i 天不持有股票时的最大现金
        dp = [[0] * 2 for _ in range(length)]
        
        # 初始化第一天的状态
        dp[0][0] = -prices[0]  # 第 0 天买入股票
        dp[0][1] = 0  # 第 0 天不持有股票
        
        # 动态规划,计算每一天的状态
        for i in range(1, length):
            # 第 i 天持有股票的最大现金
            dp[i][0] = max(dp[i - 1][0], -prices[i])
            # 第 i 天不持有股票的最大现金
            dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0])
        
        # 最终结果是最后一天不持有股票时的最大现金
        return dp[-1][1]

力扣题目链接
题目文章讲解
题目视频讲解

二、力扣122. 买卖股票的最佳时机II

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。
示例
输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3。
最大总利润为 4 + 3 = 7 。

在这个问题中,我们需要找到一个策略,使得通过多次交易(买入和卖出股票)能够获得的最大利润。与之前只能进行一次交易的情况不同,这里允许在多个不同的时间点进行多次交易,每次交易只能持有一股股票。

我们仍然使用动态规划来解决这个问题。我们定义两个状态:

dp[i][0] 表示第 i 天持有股票时能够获得的最大现金金额。
dp[i][1] 表示第 i 天不持有股票时能够获得的最大现金金额。

与只能进行一次交易不同,这里第 i 天买入股票的现金金额可以是前一天不持有股票时的现金减去今天的股票价格,即 dp[i-1][1] - prices[i]。

持有股票时 (dp[i][0]):

如果第 i-1 天已经持有股票,那么保持现状:dp[i-1][0]。
如果第 i 天买入股票,那么所得现金为前一天不持有股票的现金减去今天的股票价格:dp[i-1][1] - prices[i]。
公式:dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i])

不持有股票时 (dp[i][1]):

如果第 i-1 天已经不持有股票,那么保持现状:dp[i-1][1]。
如果第 i 天卖出股票,那么所得现金为今天的股票价格加上前一天持有股票的现金:dp[i-1][0] + prices[i]。
公式:dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i])

代码实现

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        length = len(prices)
        
        # 特殊情况处理
        if length == 0:
            return 0
        
        # 初始化 dp 数组,大小为 [length][2]
        # dp[i][0] 表示第 i 天持有股票时的最大现金
        # dp[i][1] 表示第 i 天不持有股票时的最大现金
        dp = [[0] * 2 for _ in range(length)]
        
        # 初始化第一天的状态
        dp[0][0] = -prices[0]  # 第 0 天买入股票
        dp[0][1] = 0  # 第 0 天不持有股票
        
        # 动态规划,计算每一天的状态
        for i in range(1, length):
            # 第 i 天持有股票的最大现金
            dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i])
            # 第 i 天不持有股票的最大现金
            dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i])
        
        # 最终结果是最后一天不持有股票时的最大现金
        return dp[-1][1]

力扣题目链接
题目文章讲解
题目视频讲解

二、力扣123. 买卖股票的最佳时机III

给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例
输入:prices = [3,3,5,0,0,3,1,4]
输出:6
解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。
随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。

在这个问题中,我们需要找到一个策略,通过最多两次交易(即最多买入两次和卖出两次)来获得最大利润。每次交易只能持有一股股票,因此有五种状态:

dp[i][0]:表示第 i 天没有任何操作或不进行任何交易时的最大利润。
dp[i][1]:表示第 i 天进行了第一次买入操作后的最大利润。
dp[i][2]:表示第 i 天进行了第一次卖出操作后的最大利润。
dp[i][3]:表示第 i 天进行了第二次买入操作后的最大利润。
dp[i][4]:表示第 i 天进行了第二次卖出操作后的最大利润。

dp[i][1]: 第 i 天持有股票(第一次买入)的最大利润:
如果第 i 天买入股票:dp[i-1][0] - prices[i]。
如果第 i 天不买入股票:dp[i-1][1]。
公式:dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])

dp[i][2]: 第 i 天不持有股票(第一次卖出)的最大利润:
如果第 i 天卖出股票:dp[i-1][1] + prices[i]。
如果第 i 天不卖出股票:dp[i-1][2]。
公式:dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i])

dp[i][3]: 第 i 天持有股票(第二次买入)的最大利润:
如果第 i 天买入股票:dp[i-1][2] - prices[i]。
如果第 i 天不买入股票:dp[i-1][3]。
公式:dp[i][3] = max(dp[i-1][3], dp[i-1][2] - prices[i])

dp[i][4]: 第 i 天不持有股票(第二次卖出)的最大利润:
如果第 i 天卖出股票:dp[i-1][3] + prices[i]。
如果第 i 天不卖出股票:dp[i-1][4]。
公式:dp[i][4] = max(dp[i-1][4], dp[i-1][3] + prices[i])

dp数组初始化

dp[0][0] = 0:表示第 0 天不进行任何操作,利润为 0。
dp[0][1] = -prices[0]:表示第 0 天第一次买入股票后的利润,即减去第 0 天的股票价格。
dp[0][2] = 0:表示第 0 天第一次卖出股票后的利润,因为不能卖出不存在的股票,所以利润为 0。
dp[0][3] = -prices[0]:表示第 0 天第二次买入股票后的利润,即再减去第 0 天的股票价格。
dp[0][4] = 0:表示第 0 天第二次卖出股票后的利润,同理也为 0。

代码实现

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        # 特殊情况处理,如果没有股票价格数据,返回 0
        if len(prices) == 0:
            return 0
        
        # 初始化 dp 数组,大小为 [len(prices)][5]
        dp = [[0] * 5 for _ in range(len(prices))]
        
        # 第 0 天的状态初始化
        dp[0][0] = 0  # 不操作
        dp[0][1] = -prices[0]  # 第一次买入
        dp[0][2] = 0  # 第一次卖出
        dp[0][3] = -prices[0]  # 第二次买入
        dp[0][4] = 0  # 第二次卖出
        
        # 动态规划,遍历每一天的状态
        for i in range(1, len(prices)):
            # 第 i 天不操作的状态,延续前一天的状态
            dp[i][0] = dp[i-1][0]
            # 第 i 天第一次买入股票的状态
            dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])
            # 第 i 天第一次卖出股票的状态
            dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i])
            # 第 i 天第二次买入股票的状态
            dp[i][3] = max(dp[i-1][3], dp[i-1][2] - prices[i])
            # 第 i 天第二次卖出股票的状态
            dp[i][4] = max(dp[i-1][4], dp[i-1][3] + prices[i])
        
        # 最终返回的结果是最后一天,第二次卖出股票后的最大利润
        return dp[-1][4]

力扣题目链接
题目文章讲解
题目视频讲解

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

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

相关文章

【计算机系统架构】从0开始构建一台现代计算机|时序逻辑、主存储器|第3章

博主简介:努力学习的22级计算机科学与技术本科生一枚🌸博主主页: Yaoyao2024往期回顾: 【计算机系统架构】从0开始构建一台现代计算机|二进制、布尔运算和ALU|第2章每日一言🌼: 孤独和喧嚣都令人难以忍受。如果一定要忍…

【精选】基于B_S架构的智慧校园系统的设计与实现(全网独一无二,阿龙原创开发)

博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…

5分钟搞定!最好用的6款写论文专用神器APP软件

在当今学术研究和写作领域,AI论文写作工具的出现极大地提高了写作效率和质量。这些工具不仅能够帮助研究人员快速生成论文草稿,还能进行内容优化、查重和排版等操作。以下是8款推荐的AI论文写作工具,包括千笔-AIPassPaper,帮助你更…

AOP自定义注解防重

Spring Boot 防重提交注解实现与实战示例 在Web开发中,防止用户重复提交表单是一个常见的需求。本文将详细介绍如何在Spring Boot中通过自定义注解和AOP技术实现防重提交功能,并提供一个完整的示例。 一、背景介绍 重复提交问题通常出现在用户在短时间…

来自OpenAI官网的Function calling介绍与最佳实践

学习如何将大型语言模型连接到外部工具。 介绍 函数调用允许您将模型如gpt-4o与外部工具和系统连接起来。这对于许多事情都很有用,比如为AI助手赋能,或者在你的应用程序与模型之间建立深度集成。 在2024年8月,我们推出了结构化输出功能。当…

8月27日笔记

活动目录的访问 AD Explorer LDAP( Lightweight Directory Access Protocol,轻量目录访问协议)是一种基于TCP/IP的应用层协议,用于访问和维护分布式目录信息服务。它允许用户在一个网络中查找和管理存储在目录服务中的信息。是在…

SCADA 系统开启车间智能可视化

在当今高速发展的工业时代,车间的高效运作与精准管理至关重要。然而在自动化设备、仪表、传感器等应用的现今,其产生的数据越来越庞大,要想将这些数据充分利用起来,并且形成更易分析的信息,则需要SCADA 系统来进行采集…

参数高效的迁移学习在自然语言处理中的应用

人工智能咨询培训老师叶梓 转载标明出处 迁移学习技术,尤其是针对大型预训练模型的微调(fine-tuning),在诸多下游任务中展现出了卓越的性能。然而,当面临众多任务时,传统的微调方法存在参数效率低下的问题…

鸿蒙开发:深入浅出Stage模型(UIAbility组件)

🚀一、UIAbility组件 🔎1.概述 HarmonyOS中的Stage模型是一种基于UIAbility组件的应用程序架构。UIAbility是HarmonyOS系统中用于构建用户界面的基本组件之一。它负责处理应用程序界面的显示和交互。 在Stage模型中,每个应用程序都有一个或…

【Qt笔记】QCommandLinkButton控件详解

目录 引言 一、概述 二、特性与属性 1. 属性 2. 样式 三、基本用法 1. 引入必要的头文件 2. 创建和配置 QCommandLinkButton 3. 布局管理 四、高级用法 1. 自定义绘制 2. 动态内容更新 五、代码解析示例 注意 总结 引言 QCommandLinkButton 是 Qt 框架中 QtWi…

招生简章如何制作为在线版的网址链接?

​随着互联网的高速发展,越来越多的学校和企业选择通过在线方式发布招生简章。这种趋势不仅方便了大量用户,还大大降低了传统纸质招生简章的制造成本。那么,如何制作一份吸引眼球的在线招生简章呢? 1.要制作电子杂志,首先需要选择…

leetcode_001_两数之和解析

两数之和解析 题目: 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。你可以按任意顺序…

【解压即玩】使命de召唤4

《使命de召唤4》 立即下载:【chumenx.com】【解压即玩】使命de召唤4

Leetcode 51. 皇后 回溯 C++实现

Leetcode 51. 皇后 问题:按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上,并且使皇后彼此之间不能相互攻击。 给你一个整数 n ,返回所有不…

Spring框架基础

前言 本文将讲解spring框架的基础内容 Spring 首先,我们需要了解,spring是什么? spring是一个轻量级的IOC和AOP的一站式java开发框架 作用是简化企业级开发 轻量级:框架体积小(核心模块) 其中 IOC: Inversion of Control 控制反转 IOC的作用是可以把创建对象的控制权,反转给s…

学习区块链?看我就够了!

写在前面,本文提到的所有书籍资源,都提供免费下载地址 内含pdf,epub,mobi等格式 一.区块链:定义未来金融与经济新格局 以区块链技术为核心构建的价值互联网 将深刻改变未来的金融与经济格局 文明向前发展,有些成果的…

Linux基础软件-共享存储nfs

作者介绍:简历上没有一个精通的运维工程师。希望大家多多关注作者,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 Linux进阶部分又分了很多小的部分,我们刚讲完了Linux日常运维。讲的那些东西都算是系统自带的,但是Linux作为一个…

大模型之二十七-语音识别Whisper实例浅析

Whisper简介 Whisper是OpenAI于2022年9月开源的一个多语种识别模型,目前支持99种语言,是目前性能最好的开源多语种识别ASR大模型,第一版版使用了68万小时标注好的语料预训练模型,而large-v3的标注数据超过了500万小时&#xff0c…

QL5010-16-ASEMI逆变焊机专用整流桥QL5010

编辑:ll QL5010-16-ASEMI逆变焊机专用整流桥QL5010 型号:QL5010 品牌:ASEMI 封装:KBPC-4 批号:2024 类型:整流模块 电流:50A 电压:1600V 安装方式:直插式封装 …

(2)Studio 5000 Logix Emulate仿真使用方法

Studio 5000 Logix Emulate仿真使用方法 引言:首先要安装好Studio 5000 logix emulate,这个软件也是需要授权的。还需要注意仿真器与studio 5000之间版本的对应,studio5000的版本需要小于仿真器版本。 打开Studio 5000 logix emulate&#x…