【Leetcode】DP | 买卖股票的最佳时机,DP居然还可以用状态机?

news2024/11/16 23:56:28

带状态的DP君~

  • 类型总结:买卖一次、买卖无限次、买卖k次、买卖无限次、含冷冻期。

  • 买卖k次的问题需要不断统计、维护买卖i次的最大收益。

  • 状态较多的题可以借助状态机分析状态转移情况。

121 买卖股票的最佳时机

统计第 i i i天之前的股票最低价格,计算在第 i i i天卖出时能得到的最大收益,从而得到全局的最大收益。一次遍历可以解决。

class Solution {
    public int maxProfit(int[] prices) {
        // 目前的最小价格
        int minPrice = prices[0];
        // 能够获得的最大收益
        int profit = 0;
        for (int i = 1; i < prices.length; i++) {
            // 更新收益
            profit = Math.max(profit, prices[i] - minPrice); 
            // 更新价格
            minPrice = Math.min(minPrice, prices[i]);
        }
        return profit;
    }
}

122 买卖股票的最佳时机Ⅱ

贪心(不好意思啦作弊啦),如果当前股票价格比前一天高,那就在前一天买入、在今天卖出。

class Solution {
    public int maxProfit(int[] prices) {
        int profit = 0;
        
        for (int i = 1; i < prices.length; i++) {
            profit += Math.max(0, prices[i] - prices[i - 1]);
        }
        
        return profit;
    }
}

123 买卖股票的最佳时机Ⅲ ★

思路可能不难,但细节确实太多。

以第一次买入、第一次卖出、第二次买入、第二次卖出作为4个状态。

先考虑在第i天时的情况

D[i][0] 在第i天第一次买入股票的收益: -prices[i]
D[i][1] 在第i天第一次卖出股票的最大收益: prices[i] - min(prices[j]), j <= i
D[i][2] 在第i天第二次买入股票的最大收益: -prices[i] + max(D[j][1]), j <= i
D[i][3] 在第i天第二次卖出股票的最大收益: prices[i] + max(D[j][2]), j <= i

在考虑在第i天及之前的情况

需要的统计量包括:

1、第 i i i天之前股票的最小价格
minPrice ( i ) = min ⁡ ( minPrice ( i − 1 ) ,   p r i c e s [ i ] ) \text{minPrice}(i) = \min(\text{minPrice}(i - 1),\ prices[i]) minPrice(i)=min(minPrice(i1), prices[i])
2、第 i i i天及之前第一次卖出股票能得到的最大收益

  • 可以在同一天先买入后卖出,至少这样第一笔交易不会是负收益,故减去 m i n P r i c e ( i ) minPrice(i) minPrice(i),而不是减去 m i n P r i c e ( i − 1 ) minPrice(i - 1) minPrice(i1)

sell 1 ( i ) = max ⁡ ( sell 1 ( i − 1 ) ,   p r i c e s [ i ] − minPrice ( i ) ) \text{sell}_1(i) = \max(\text{sell}_1(i-1),\ prices[i] - \text{minPrice}(i)) sell1(i)=max(sell1(i1), prices[i]minPrice(i))

3、第 i i i天及之前第二次买入股票能得到的最大收益
buy 2 ( i ) = max ⁡ ( buy 2 ( i − 1 ) ,   − p r i c e s [ i ] + sell 1 ( i ) ) \text{buy}_2(i) = \max(\text{buy}_2(i-1),\ -prices[i] + \text{sell}_1(i)) buy2(i)=max(buy2(i1), prices[i]+sell1(i))
4、第 i i i天及之前第二次卖出股票能得到的最大收益:
sell 2 ( i ) = max ⁡ ( sell 2 ( i − 1 ) ,   p r i c e s [ i ] + buy 2 ( i ) ) \text{sell}_2(i) = \max(\text{sell}_2(i-1),\ prices[i] + \text{buy}_2(i)) sell2(i)=max(sell2(i1), prices[i]+buy2(i))
写成代码类似物,变量的更新方式如下:

第i天及之前:
股票的最小价格:buy1 = min(buy1, prices[i])
第一次卖出股票能得到的最大收益:sell1 = max(sell1, prices[i] - buy1)
第二次买入股票的最大收益:buy2 = max(buy2, -prices[i] + sell1)
第二次卖出股票能获得的最大收益:sell2 = max(sell2, prices[i] + buy2)

完整代码,代码非常简介,分析非常复杂:

class Solution {
    public int maxProfit(int[] prices) {
        int minPrice = Integer.MAX_VALUE;
        int sell1 = Integer.MIN_VALUE;
        int buy2 = Integer.MIN_VALUE;
        int sell2 = Integer.MIN_VALUE;

        for (int i = 0; i < prices.length; i++) {
            minPrice = Math.min(prices[i], minPrice);
            sell1 = Math.max(sell1, prices[i] - minPrice);
            buy2 = Math.max(buy2, -prices[i] + sell1);
            sell2 = Math.max(sell2, prices[i] + buy2);
        }

        return sell2;
    }
}

188 买卖股票的最佳时机Ⅳ

最多可以买 k k k次啦,建议写完Ⅲ再来写Ⅳ,要不真的思考过程too hard。

i i i天及之前第k次买入的最大收益:
b u y k ( i ) = max ⁡ ( b u y k ( i − 1 ) , − p r i c e s [ i ] + s e l l k − 1 ( i ) ) buy_k(i) = \max(buy_k(i - 1), -prices[i]+sell_{k-1}(i)) buyk(i)=max(buyk(i1),prices[i]+sellk1(i))
i i i天及之前第k次卖出的最大收益:
s e l l k ( i ) = max ⁡ ( s e l l k ( i − 1 ) , p r i c e s [ i ] + b u y k ( i ) ) sell_k(i)=\max(sell_k(i-1), prices[i]+buy_k(i)) sellk(i)=max(sellk(i1),prices[i]+buyk(i))
所以需要一个数组捏:int[][] D = new int[k + 1][2]

遍历整个数组,遍历到每一个元素时,更新D。

D[k][0] = max(D[k][0], -prices[i] + D[k - 1][1])
D[k][1] = max(D[k][1], prices[i] + D[k][0])

初始化:

D[k][0] = -inf
D[k][1] = 0

完整代码:

class Solution {
    public int maxProfit(int k, int[] prices) {
        // D[j][0]表示第j次买入的最大收益,D[j][1]表示第j次卖出的最大收益,j从1到k
        int[][] D = new int[k + 1][2];

        for (int j = 0; j <= k; j++) {
            D[j][0] = Integer.MIN_VALUE;
        }

        for (int price : prices) {
            for (int j = 1; j <= k; j++) {
                D[j][0] = Math.max(D[j][0], -price + D[j - 1][1]);
                D[j][1] = Math.max(D[j][1], price + D[j][0]);
            }
        }

        return D[k][1];
    }
}

309 最佳买卖股票时机含冷冻期

分析不明白了捏,画个状态机看看。

D [ i ] [ 0 ] , D [ i ] [ 1 ] , D [ i ] [ 2 ] D[i][0], D[i][1], D[i][2] D[i][0],D[i][1],D[i][2]表示第 i i i在未持有、持有、冷冻期状态的最大收益

  • i i i天若为持有状态,可由第 i − 1 i-1 i1天的 <持有状态 + 不卖动作> 和第 i − 1 i-1 i1天的 <未持有状态 + 买入动作> 转移而来
    • <持有状态 + 不卖动作> : D [ i − 1 ] [ 1 ] D[i-1][1] D[i1][1]
    • <未持有状态 + 买入动作>: − p r i c e s [ i ] + D [ i − 1 ] [ 0 ] -prices[i] + D[i-1][0] prices[i]+D[i1][0]
    • D [ i ] [ 1 ] = max ⁡ ( D [ i − 1 ] [ 1 ] , − p r i c e s [ i ] + D [ i − 1 ] [ 0 ] ) D[i][1] = \max(D[i-1][1], -prices[i] + D[i-1][0]) D[i][1]=max(D[i1][1],prices[i]+D[i1][0])
  • i i i天若为未持有状态,可由第 i − 1 i-1 i1天的 <冷冻期 + 过一天> 和第 i − 1 i-1 i1天的 <未持有状态 + 不买动作> 转移而来
    • <冷冻期 + 过一天> : D [ i − 1 ] [ 2 ] D[i-1][2] D[i1][2]
    • <未持有状态 + 不买动作>: D [ i − 1 ] [ 0 ] D[i-1][0] D[i1][0]
    • D [ i ] [ 0 ] = max ⁡ ( D [ i − 1 ] [ 0 ] , D [ i − 1 ] [ 2 ] ) D[i][0] = \max(D[i-1][0], D[i-1][2]) D[i][0]=max(D[i1][0],D[i1][2])
  • i i i天若为冷冻期:
    • <持有状态 + 卖出>: D [ i ] [ 2 ] = D [ i − 1 ] [ 1 ] + p r i c e s [ i ] D[i][2] = D[i-1][1]+prices[i] D[i][2]=D[i1][1]+prices[i]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TuEj2YNd-1686482336665)(【Leetcode】DP-股票系列,买卖股票的最佳时机/image-20230611140915336.png)]

代码:

class Solution {
    public int maxProfit(int[] prices) {
        int hold = Integer.MIN_VALUE;
        int freeze = 0;
        int notHold = 0;

        int profit = Integer.MIN_VALUE;

        for (int i = 0; i < prices.length; i++) {
            hold = Math.max(hold, -prices[i] + notHold);
            notHold = Math.max(notHold, freeze);
            freeze = hold + prices[i];
            
            profit = Math.max(profit, freeze);
        }

        return profit;
    }
}

714 买卖股票的最佳时机含手续费

和Ⅱ蛮像,状态机确实好使。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Eu31b4O6-1686482336666)(【Leetcode】DP-股票系列,买卖股票的最佳时机/image-20230611143118427.png)]

有手续费的话就不会出现当日买入、当日卖出的情况啦,负收益捏。

  1. i i i天为持有状态的最大收益:
    • <未持有 + 买入>: − p r i c e s [ i ] + D [ i − 1 ] [ 1 ] -prices[i] + D[i-1][1] prices[i]+D[i1][1]
    • <持有 + 不卖>: D [ i − 1 ] [ 0 ] D[i-1][0] D[i1][0]
  2. i i i天为未持有状态的最大收益:
    • <持有 + 卖出>: p r i c e s [ i ] − f e e + D [ i − 1 ] [ 0 ] prices[i] -fee + D[i-1][0] prices[i]fee+D[i1][0]
    • <未持有 + 不卖>: D [ i − 1 ] [ 1 ] D[i-1][1] D[i1][1]
class Solution {
    public int maxProfit(int[] prices, int fee) {
        int hold = Integer.MIN_VALUE;
        int notHold = 0;

        int profit = 0;

        for (int i = 0; i < prices.length; i++) {
            hold = Math.max(hold, -prices[i] + notHold);
            notHold = Math.max(notHold, prices[i] - fee + hold);
            // 更新最大收益
            profit = Math.max(profit, notHold);
        }

        return profit;
    }
}

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

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

相关文章

性能测试项目实战:应用加载慢该怎么办?

背景 app收到留学push、课堂、资讯&#xff0c;用户点击push消息&#xff0c;进入app&#xff0c;应用加载很慢&#xff0c;容易出现应用假死、app崩溃或提示网络异常等信息。 给用户体验十分不友好&#xff0c;监控阿里云资源tcp连接数飙高&#xff0c;cpu打满&#xff0c…

Nginx运行原理与基本配置文件讲解

文章目录 Nginx基本运行原理Nginx的基本配置文件serverlocationroot 与 alias 的区别server 和 location 中的 rootnginx欢迎页 本文参考文章Nginx相关文章 Nginx基本运行原理 Nginx的进程是使用经典的「Master-Worker」模型,Nginx在启动后&#xff0c;会有一个master进程和多个…

docker-compose编排容器

系列文章目录 文章目录 系列文章目录一、docker-compose1.Docker Compose2.YAML 文件格式及编写注意事项3.安装docker-compose4.Docker Compose配置常用字段 二、创建compose1.准备依赖文件2. 总结 一、docker-compose 1.Docker Compose 如果需要定义多个容器就需要服务编排。…

priority_queue的模拟实现

前言 优先级队列听名字好像与队列有关&#xff0c;但是实际上&#xff0c;与队列没有很多关系&#xff0c;它也是容器适配器&#xff0c;是通过vector来适配的&#xff0c;但是里面又加入了堆的调整算法。跟栈和队列又有一些不同&#xff0c;了解它的实现对于我们更好的掌握它是…

新手上路,安全驾驶,做行车安全的第一责任人

目录 一、生活与汽车二、树立安全意识三、掌握驾驶经验四、参考材料 道路千万条&#xff0c;安全第一条&#xff0c;行车不规范&#xff0c;亲人两行泪。 ——《流浪地球》 一、生活与汽车 开车是为了节省在路途上花费的时间&#xff0c;片面的追求交通效率会引发交通安全问题&…

day8 栈顶的种类与应用

目录 多寄存器访问指令与寻址方式 多寄存器内存访问指令 多寄存器内存访问指令的寻址方式 ​编辑 栈的种类与使用 栈的概念 栈的分类 栈的应用举例 叶子函数的调用过程举例 多寄存器访问指令与寻址方式 多寄存器内存访问指令 MOV R1, #1 MOV R2, #2 MOV R3, #3 MOV R…

Redis 持久化存储机制:RDB 和 AOF

Redis&#xff08;Remote Dictionary Server&#xff09;是一个高性能的键值存储系统&#xff0c;它可以将数据存储在内存中以实现快速访问。为了保持数据的持久性&#xff0c;Redis 提供了两种数据持久化方法&#xff1a;RDB 和 AOF。 RDB&#xff08;Redis Database&#xff…

spring源码-代码的特殊写法

spring源码-代码的特殊写法 前言 在阅读spring源码中&#xff0c;可能会有很多种代码写法在工作中都没遇见过&#xff0c;阅读起来有一定的难度&#xff0c;在本文中&#xff0c;我会把我认为有难度的代码写法拿出来&#xff0c;并举例子说明清楚&#xff0c;方便大家阅读并理…

股价暴涨59%后,美股二手车平台Carvana在短期内还会进一步上涨?

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 Carvana(CVNA)股票在财报发布近一个月后又重新开始出现了上涨。 仅6月9日就上涨了59%。 相对于纳斯达克综合指数的上涨幅度&#xff0c;Carvana今年迄今为止的上涨幅度已经比纳斯达克综合指数高出了约400%。 Carvana最…

RabbitMQ - 死信队列,延时队列

Time-To-Live and Expiration — RabbitMQ 一、死信队列 Dead Letter Exchanges — RabbitMQ 死信队列&#xff1a; DLX 全称&#xff08;Dead-Letter-Exchange&#xff09;,称之为死信交换器&#xff0c;当消息变成一个死信之后&#xff0c;如果这个消息所在的队列存在x-d…

全球、全国遥感土地利用数据产品下载(1m、10m、30m分辨率,内含链接与详细教程)

土地利用/覆被数据能够获取地表覆被信息&#xff0c;同时也是地球系统科学学科的基础数据&#xff08;如生态、水文、地质等&#xff09;吗&#xff0c;目前&#xff0c;基于遥感生成的土地利用/覆被数据产品比较多样&#xff0c;本文整理了目前应用比较多的7种数据产品进行介绍…

Hazel游戏引擎(007)Premake

文中若有代码、术语等错误&#xff0c;欢迎指正 文章目录 前言操作步骤premake写lua脚本文件执行premake.exe文件效果 前言 此节目的 由于之前配置VS项目各项属性需要根据不同平台手动一个一个设置&#xff0c;很麻烦&#xff0c;缺乏灵活性。 用lua脚本配置项目属性&#xff0…

基于Java+SpringBoot的鞋类商品购物商城系统设计与实现

博主介绍&#xff1a;✌擅长Java、微信小程序、Python、Android等&#xff0c;专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案…

业务部门的通病:想搞了大而全的软件

业务部门的通病&#xff1a;想搞个大而全的软件 怎么样评价软件功能的价值重要性&#xff1f; 软件的消耗成本是惊人的 中小企业一定要约束需求 做SaaS的香港上市公司有赞&#xff08;做商城软件&#xff09; 10年了还在亏损 趣讲大白话&#xff1a;大而全的功能是陷阱 【趣讲信…

Geek-PC项目 文档

一款后台管理项目 - React-geek-PC 项目介绍 ● 项目功能演示 - 登录、退出 - 首页 - 内容&#xff08;文章&#xff09;管理&#xff1a;文章列表、发布文章、修改文章● 技术 - React 官方脚手架 create-react-app - react hooks - 状态管理&#xff1a;mobx - UI 组件库…

ESP32网络应用 -- ESP32-S3在STA模式下创建TCP-CLIENT应用程序

在ESP32-S3初始化为Station模式并且成功获取IP地址后,说明ESP32-S3芯片的底层设施已经具备Wi-Fi网络通信能力,但在实际的应用场景里面,仅仅建立数据链路层,还是不能够满足应用程序的数据通信需求。 TCP/IP是一种使用广泛的网络传输协议,网络上并不缺乏关于TCP/IP的具体原…

Atcoder Beginner Contest 304——A-D题讲解

蒟蒻来讲题&#xff0c;还望大家喜。若哪有问题&#xff0c;大家尽可提&#xff01; Hello, 大家好哇&#xff01;本初中生蒟蒻讲解一下AtCoder Beginner Contest 304这场比赛的A-D题&#xff01; A - First Player 题目描述 Problem Statement There are N N N people nu…

sequence2sequence

1. 基本模型 所谓的Seq2seq模型从字面上理解很简单&#xff0c;就是由一个序列到另一个序列的过程(比如翻译、语音等方面的应用)&#xff1a; 那么既然是序列模型&#xff0c;就需要搭建一个RNN模型(神经单元可以是GRU模型或者是LSTM模型) 下面两篇文章提出了这样的seq2seq的模…

NVM安装教程

我是小荣&#xff0c;给个赞鼓励下吧&#xff01; NVM安装教程 简介 nvm 是node.js的版本管理器&#xff0c;设计为按用户安装&#xff0c;并按 shell 调用。nvm适用于任何符合 POSIX 的 shell&#xff08;sh、dash、ksh、zsh、bash&#xff09;&#xff0c;特别是在这些平台…

ChatGPT 五个写论文的神技巧,让你的老师对你刮目相看!

导读&#xff1a;ChatGPT这款AI工具在推出两个月内就累积了超过1亿用户。我们向您展示如何使用ChatGPT进行写作辅助&#xff0c;以及其他一些有用的写作技巧。 本文字数&#xff1a;2000&#xff0c;阅读时长大约&#xff1a;12分钟 ChatGPT这款AI工具在推出两个月内就累积了超…