代码随想录算法训练营第五十天| LeetCode123. 买卖股票的最佳时机 III、LeetCode188. 买卖股票的最佳时机 IV

news2024/11/30 9:47:33

一、LeetCode123. 买卖股票的最佳时机 III

        1:题目描述(123. 买卖股票的最佳时机 III)

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

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

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

        2:解题思路

        本题关键在于至多买卖两次,这意味着可以买卖一次,可以买卖两次,也可以不买卖

动态规划五部曲详细分析:

        1:确定dp数组以及下标的含义

        一天一共就有五个状态,

                0:没有操作

                1:第一次买入

                2:第一次卖出

                3:第二次买入

                4:第二次卖出

        dp[i][j]中 i表示第i天,j为 [0 - 4] 五个状态,dp[i][j]表示第i天状态j所剩最大现金。

        2:确定递推公式

        需要注意:dp[i][1],表示的是第i天,买入股票的状态,并不是说一定要第i天买入股票,这是很多同学容易陷入的误区

        达到dp[i][1]状态,有两个具体操作:

  • 操作一:第i天买入股票了,那么dp[i][1] = dp[i-1][0] - prices[i]
  • 操作二:第i天没有操作,而是沿用前一天买入的状态,即:dp[i][1] = dp[i - 1][1]

        那么dp[i][1]究竟选 dp[i-1][0] - prices[i],还是dp[i - 1][1]呢?

        一定是选最大的,所以 dp[i][1] = max(dp[i-1][0] - prices[i], dp[i - 1][1]);

        同理dp[i][2]也有两个操作:

  • 操作一:第i天卖出股票了,那么dp[i][2] = dp[i - 1][1] + prices[i]
  • 操作二:第i天没有操作,沿用前一天卖出股票的状态,即:dp[i][2] = dp[i - 1][2]

        所以dp[i][2] = max(dp[i - 1][1] + prices[i], dp[i - 1][2])

        同理可推出剩下状态部分:

        dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i]);

        dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]);

        3:dp数组如何初始化

        第0天没有操作,这个最容易想到,就是0,即:dp[0][0] = 0;

        第0天做第一次买入的操作,dp[0][1] = -prices[0];

        第0天做第一次卖出的操作,这个初始值应该是多少呢?

        首先卖出的操作一定是收获利润,整个股票买卖最差情况也就是没有盈利即全程无操作现金为0,

        从递推公式中可以看出每次是取最大值,那么既然是收获利润如果比0还小了就没有必要收获这个利润了。

        所以dp[0][2] = 0;

        第0天第二次买入操作,初始值应该是多少呢?应该不少同学疑惑,第一次还没买入呢,怎么初始化第二次买入呢?

        第二次买入依赖于第一次卖出的状态,其实相当于第0天第一次买入了,第一次卖出了,然后在买入一次(第二次买入),那么现在手头上没有现金,只要买入,现金就做相应的减少。

        所以第二次买入操作,初始化为:dp[0][3] = -prices[0];

        同理第二次卖出初始化dp[0][4] = 0;

        4:确定遍历顺序

        从递归公式其实已经可以看出,一定是从前向后遍历,因为dp[i],依靠dp[i - 1]的数值

        5:打印dp数组

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        prices_len = len(prices)
        if prices_len == 0:
            return 0
        # 规定每天都有5个状态:0-没有操作,1-第一次买入,2-第一次卖出,3-第二次买入,4-第二次卖出
        # dp[i][j]表示第i天状态j所剩最大现金
        dp = [[0] * 5 for _ in range(prices_len)]
        # dp[0][0] = 0
        dp[0][1] = -prices[0]         # 第一次买入,原始金额为0,所以买入后,所剩金额为-prices[0]
        # dp[0][2] = 0                
        dp[0][3] = -prices[0]         # 第二次买入,第一次买入卖出的所剩金额为0,所以买入后,所剩金额为-prices[0]
        # dp[0][4] = 0
        for i in range(1, prices_len):
            dp[i][0] = dp[i-1][0]
            # 第i天,第一次买入,
            # 1:第i-1天就已经买入,保持现状,dp[i][1] = dp[i-1][1]
            # 2:第i天买入,前一天没操作的所剩金额减去第i天的价格,dp[i][1] = dp[i-1][0] - prices[i]
            dp[i][1] = max(dp[i-1][1], dp[i-1][0]-prices[i])
            # 第一次卖出
            # 1:第i-1天就已经卖出,保持现状,dp[i][2] = dp[i-1][2]
            # 2:第i天卖出,前一天买入的所剩金额+第i天的价格,dp[i][2] = dp[i-1][1] + prices[i]
            dp[i][2] = max(dp[i-1][2], dp[i-1][1]+prices[i])
            # 第二次买入,
            # 1:第i-1天就已经买入,保持现状,dp[i][3] = dp[i-1][3]
            # 2:第i天买入,前一天卖出后的所剩金额减去第i天的价格,dp[i][3] = dp[i-1][2] - prices[i]
            dp[i][3] = max(dp[i-1][3], dp[i-1][2]-prices[i])
            # 第二次卖出
            # 1:第i-1天就已经卖出,保持现状,dp[i][4] = dp[i-1][4]
            # 2:第i天卖出,前一天买入的所剩金额+第i天的价格,dp[i][4] = dp[i-1][3] + prices[i]
            dp[i][4] = max(dp[i-1][4], dp[i-1][3]+prices[i])
        return dp[-1][4]

二、LeetCode188. 买卖股票的最佳时机 IV

        1:题目描述(188. 买卖股票的最佳时机 IV)

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

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

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

        2:解题思路

动规五部曲,分析如下:

        1:确定dp数组以及下标的含义

        使用二维数组 dp[i][j] :第i天的状态为j,所剩下的最大现金是dp[i][j]

        j的状态表示为:

  • 0 表示不操作
  • 1 第一次买入
  • 2 第一次卖出
  • 3 第二次买入
  • 4 第二次卖出
  • .....

        大家应该发现规律了吧 ,除了0以外,偶数就是卖出,奇数就是买入

        题目要求是至多有K笔交易,那么j的范围就定义为 2 * k + 1 就可以了。

        2:确定递推公式

        dp[i][1],表示的是第i天,买入股票的状态,并不是说一定要第i天买入股票,这是很多同学容易陷入的误区

        达到dp[i][1]状态,有两个具体操作

  • 操作一:第i天买入股票了,那么dp[i][1] = dp[i - 1][0] - prices[i]
  • 操作二:第i天没有操作,而是沿用前一天买入的状态,即:dp[i][1] = dp[i - 1][1]

        选最大的,所以 dp[i][1] = max(dp[i - 1][0] - prices[i], dp[i - 1][1]);

        同理dp[i][2]也有两个操作

  • 操作一:第i天卖出股票了,那么dp[i][2] = dp[i - 1][1] + prices[i]
  • 操作二:第i天没有操作,沿用前一天卖出股票的状态,即:dp[i][2] = dp[i - 1][2]

        所以dp[i][2] = max(dp[i - 1][1] + prices[i], dp[i - 1][2])

        同理可以类比剩下的状态,代码如下:

for j in range(1, 2*k+1):
    # j为奇数,买入
    if j % 2 != 0:
        # 1:第i-1天就已经买入,保持现状,dp[i][j] = dp[i-1][j]
        # 2:第i天买入,前一天没操作或卖出后的所剩金额减去第i天的价格,dp[i][j] = dp[i-1][j-1]-prices[i]
        dp[i][j] = max(dp[i-1][j], dp[i-1][j-1]-prices[i])
    # j为偶数,卖出
    else:
        # 1:第i-1天就已经卖出,保持现状,dp[i][j] = dp[i-1][j]
        # 2:第i天卖出,前一天买入的所剩金额+第i天的价格,dp[i][j] = dp[i-1][j-1] + prices[i]
        dp[i][j] = max(dp[i-1][j], dp[i-1][j-1]+prices[i])

        与123. 买卖股票的最佳时机 III最大的区别就是这里要类比j为奇数是买,偶数是卖的状态

        3:dp数组如何初始化

        第0天没有操作,这个最容易想到,就是0,即:dp[0][0] = 0;

        第0天做第一次买入的操作,dp[0][1] = -prices[0];

        第0天做第一次卖出的操作,这个初始值应该是多少呢?

        首先卖出的操作一定是收获利润,整个股票买卖最差情况也就是没有盈利即全程无操作现金为0,

        从递推公式中可以看出每次是取最大值,那么既然是收获利润如果比0还小了就没有必要收获这个利润了。

        所以dp[0][2] = 0;

        第0天第二次买入操作,初始值应该是多少呢?

        不用管第几次,现在手头上没有现金,只要买入,现金就做相应的减少。

        第二次买入操作,初始化为:dp[0][3] = -prices[0];

        所以同理可以推出dp[0][j]当j为奇数的时候都初始化为 -prices[0],代码如下:

for j in range(1, 2*k+1, 2):
    dp[0][j] = -prices[0]

        在初始化的地方同样要类比j为偶数是卖、奇数是买的状态

        4:确定遍历顺序

        从递归公式其实已经可以看出,一定是从前向后遍历,因为dp[i],依靠dp[i - 1]的数值。

        5:打印dp数组

class Solution:
    def maxProfit(self, k: int, prices: List[int]) -> int:
        prices_len = len(prices)
        if prices_len == 0:
            return 0
        # 规定每天都有(2*k+1)个状态:0-没有操作,1-第一次买入,2-第一次卖出,3-第二次买入,4-第二次卖出,
        # 依次类推,奇数买入,偶数卖出
        # dp[i][j]表示第i天状态j所剩最大现金
        dp = [[0]*(2*k+1) for _ in range(prices_len)]
        for j in range(1, 2*k+1, 2):
            # 初始化,初始化第0天,因为后面的都是由i=0推出来的
            # 没有操作,所剩的金额就是:0,在定义dp数组是,已经全部置为0,所以不用初始化了
            # 只要买入,所剩的金额就是:-prices[i],都是在奇数的时候买入,所以初始化j为奇数的情况
            dp[0][j] = -prices[0]
            # 只要卖出了,所剩的金额都是0,在定义dp数组是,已经全部置为0,所以不用初始化了     
        for i in range(1, prices_len):
            # 第i天,没有操作,前一天也没有操作,dp[i][0] = dp[i-1][0]
            dp[i][0] = dp[i-1][0]
            for j in range(1, 2*k+1):
                # j为奇数,买入
                if j % 2 != 0:
                    # 1:第i-1天就已经买入,保持现状,dp[i][j] = dp[i-1][j]
                    # 2:第i天买入,前一天没操作或卖出后的所剩金额减去第i天的价格,dp[i][j] = dp[i-1][j-1] - prices[i]
                    dp[i][j] = max(dp[i-1][j], dp[i-1][j-1]-prices[i])
                # j为偶数,卖出
                else:
                    # 1:第i-1天就已经卖出,保持现状,dp[i][j] = dp[i-1][j]
                    # 2:第i天卖出,前一天买入的所剩金额+第i天的价格,dp[i][j] = dp[i-1][j-1] + prices[i]
                    dp[i][j] = max(dp[i-1][j], dp[i-1][j-1]+prices[i])
        return dp[-1][2*k]

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

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

相关文章

小学生学Arduino---------点阵(一)静态图片显示

今天来看一下,点阵模块这一模块可以做出非常有意思的东西。 学习目标: 1、了解点阵原理 2、掌握图形绘制(心形、三角形等) 3、掌握图形显示器的功能 4、掌握led点阵屏幕的功能 5、搭建电路 6、编写程序 一、点阵的原理 LED点阵屏…

Functional Programming in Java venkat(16) Being Lazy part3

文章目录Functional Programming in Java venkat(16): Being LazyLeveraging the Laziness of StreamsIntermediate and Terminal OperationsMethod Evaluation OrderPeeking into the LazinessFunctional Programming in Java venkat(16): Being Lazy 这里是记录学习这本书 F…

linux权限详解

文章目录1.用户转换1.将普通用户转换成root1.su -2. su2.将root转换为普通用户2.文件的权限1.文件访问者的分类拥有者和other所属组2.rwx的含义3.修改权限第一种修改方式1.拥有者修改2.所属组的修改3.other的修改4.整体修改第二种修改方式666000777使用权限的修改1.拥有者用户的…

[事务]-事务概念/特性/并发问题/传播特性

1. 事务的概念 事务(Transaction)指的是一个操作序列,该操作序列中的多个操作要么都做,要么都不做,是一个不可分割的工作单位,是数据库环境中的逻辑工作单位,由DBMS中的事务管理子系统负责…

爬虫工作流程、请求与响应原理、requests库讲解

爬虫工作流程、请求与响应原理、requests库讲解 爬虫分类主要分为两大板块 web爬虫(浏览器爬虫) APP爬虫(手机端爬虫) 在这两大板块中又可以把爬虫归类为聚焦爬虫和通用爬虫 聚焦爬虫:针对某一个接口(ur…

对话框被遮罩层挡住

element-ui 解决方法一: 在el-dialog中写去掉遮罩层 :modal"false" 解决方法二: 在el-dialog中写(遮罩层是否插入至 body 元素上,若为 false,则遮罩层会插入至 Dialog 的父元素上) :modal-ap…

[附源码]SSM计算机毕业设计医院挂号系统JAVA

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

专业硕士招生占比将达到三分之二,那么跟学术硕士有哪些区别?

近年来的研究生招生考试中,专业硕士的招生培养规模正稳步增长。据统计,2009年专业学位硕士招生人数在硕士招生总人数中的占比仅为15.9%,其后在2017年首次超过学硕招生人数,到2020年专硕招生人数占比已超60%。国务院学位委员会、教…

SpringBoot - 集成Actuator(应用信息显示、修改系统日志、增加账号密码登录)

文章目录Actuator概述官网入口支持的埋点信息查询、修改使用访问actuator埋点信息添加账号密码登录验证动态修改日志级别Actuator 概述 官网入口 官网: https://docs.spring.io/spring-boot/docs/2.7.6/reference/html/actuator.html#actuator.endpoints 支持的埋…

csdn中书写数学公式简单介绍

参考:https://www.zybuluo.com/codeep/note/163962#3%E5%9C%A8%E5%AD%97%E7%AC%A6%E9%97%B4%E5%8A%A0%E5%85%A5%E7%A9%BA%E6%A0%BC 常识、常用 一行公式使用$$开始和结尾,常用符号表示 符号功能$$多行公式的开始和结尾,一个$表示单行公式开…

Cisco ASA基础——安全算法与基本配置

作者简介:一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 目录 前言 本章重点 一.Cisco防火墙简介 1.什么是防火墙 2.防火墙的作用…

PHP表单处理的案例分析

目录 知识补充 实现过程 前端代码 后端代码 简单分析 知识补充 表单简介(来自Mr._Dang) action:提交的地址 method:提交的方式 get: 参数是在url中的,不安全,传输量比较少&#xff…

[附源码]Python计算机毕业设计Django的在线作业批改系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

[附源码]Python计算机毕业设计SSM力高灯饰线上交易平台(程序+LW)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

一言不合就重构

hello,大家好呀,我是小楼。 前段时间不是在忙么,忙的内容之一就是花了点时间重构了一个服务的健康检查组件,目前已经慢慢在灰度线上,本文就来分享下这次重构之旅,也算作个总结吧。 背景 服务健康检查简介…

短视频创作,变现的建议、变现方式和举例,建议收藏反复阅读-上

先说今天的纲要,有兴趣可以继续看下去,今天主要针对短视频变现这件事的讨论,有三个建议,①变现标准低、②变现天花板高、③可主动变现。 我们在选择变现形式的时候,尽可能满足这三个条件或其中两个。 中间我们再讨论下…

【LeetCode】895.最大频率栈

题目描述 设计一个类似堆栈的数据结构,将元素推入堆栈,并从堆栈中弹出出现频率最高的元素。 实现 FreqStack 类: FreqStack() 构造一个空的堆栈。void push(int val) 将一个整数 val 压入栈顶。int pop() 删除并返回堆栈中出现频率最高的元素。 如果出现…

【问题思考总结】NAT的公有地址怎么转换为私有地址?【MAC地址和IP地址的转换】

问题起源 在做一道题的时候,涉及到了由内网到外网再到内网时的IP地址转换。在外网的时候,答案说的是不能够用私有IP地址作为源IP地址,然后疑问产生了:如果不能用私有IP地址作为目的地址,他又怎么能够找到那个主机呢&a…

[附源码]Python计算机毕业设计SSM乐多多宠物店网站(程序+LW)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

2022年11月30日 Fuzzy C-Means学习笔记

​ Fuzzy C-Means 模糊c均值聚类,它的一大优势就是引入了一个隶属度的概念,没有对样本进行非黑即白的分类,而是分类的时候乘上隶属度,直白点说就是他和某个中心有多像,到底是40%像还是70%像。 ​ 参考:在众…