代码随想录算法训练营DAY48|C++动态规划Part9|121.买卖股票的最佳时机、122.买卖股票的最佳时机II、123.买卖股票的最佳时机III

文章目录

  • 121.买卖股票的最佳时机
    • 思路
    • CPP代码
  • 122.买卖股票的最佳时机II
    • 思路
    • CPP代码
  • 123.买卖股票的最佳时机III
    • 思路
    • CPP代码

121.买卖股票的最佳时机

力扣题目链接

文章讲解:121.买卖股票的最佳时机

视频讲解:动态规划之 LeetCode:121.买卖股票的最佳时机1

状态:非常与众不同的动态规划题,也是一类典型的动态规划题。

思路

  • dp数组的含义

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

最终要求的结果就是最后一天的状态:max(dp[len-1][0], dp[len-1][i])

并且应该注意的是,我们这里是第i天持有这支股票,并不代表我在第i天才买,我有可能之前就买了;同理,我们第i天不持有这支股票并不代表我第i天才卖。并且我们在最后拿结果的时候,肯定是dp[len(prices)][1],因为无论怎么着,我们不持有这支股票获利肯定都比在最后一天还持有股票来的高

  • 递推公式

    • 先讨论一下dp[i][0]

      • 首先确定do[i][0]表示第i天持有这支股票,那么dp[i-1][0]呢?其实他们两个是相等的, 因为我们前后两天都是持有股票;

        再一个,我们我们是在第i天才买入这支股票的话,那么也就是说我在i-1天是不持有这支股票的,并且在第i天花了买股票的钱所以直接dp[i][0]直接就是-price[i]

        综上所述:dp[i][0]=max(dp[i-1][0], -prices[i])

    • 再就是dp[i][1]

      • 同理,我们的前一天也可以是不持有这支股票的状态dp[i-1][1],此时的话和dp[i][1]他们两个相等
      • 那么如果,我们在第i天把这支股票给卖了变成了dp[i][1],那么此时我们现在手里的钱就是前一天持有股票的最大金额再加上今天卖股票赚的钱dp[i-1][0]+prices[i]
      • 综上所述:dp[i][1]=max(dp[i-1][1], dp[i-1][0]+prices[i])
  • dp数组的初始化

从公式可以看出来,我们的dp[0][0]dp[0][1]是我们整个递推公式的基础,那么dp[0][0]=-prices[0]dp[0][1]=0;然后其他的均初始化为多少其实都无所谓。

  • 遍历顺序

没讲究,直接从前向后遍历

  • 举例推导dp数组

以示例1,输入:[7,1,5,3,6,4]为例,dp数组状态如下:

20210224225642465

CPP代码

我们从递推公式可以看出:

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

dp[i]只与dp[i-1]的状态有关,所以完全可以用滚动数组,也就是只需要记录 当前天的dp状态和前一天的dp状态就可以了

class Solution {
public:int maxProfit(vector<int>& prices) {int len = prices.size();vector<vector<int>> dp(2, vector<int>(2)); // 注意这里只开辟了一个2 * 2大小的二维数组dp[0][0] -= prices[0];dp[0][1] = 0;for (int i = 1; i < len; i++) {dp[i % 2][0] = max(dp[(i - 1) % 2][0], -prices[i]);dp[i % 2][1] = max(dp[(i - 1) % 2][1], prices[i] + dp[(i - 1) % 2][0]);}return dp[(len - 1) % 2][1];}
};

122.买卖股票的最佳时机II

力扣题目链接

文章链接:122.买卖股票的最佳时机II

视频链接:动态规划,股票问题第二弹 | LeetCode:122.买卖股票的最佳时机II

状态:可以实现多次买卖,这个时候最主要的不同体现在递推公式上。如果会121.买卖股票的最佳时机,本题就比较简单

思路

本题唯一的区别就是本题的股票可以买卖多次(只有一只股票,所以再次购买前要出售掉之前的股票)

所以本题和121.买卖股票的最佳时机唯一的区别就在于递推公式,其他的地方都是一样的。首先,我们重申一下dp数组的含义:dp[i][0] 表示第i天持有股票所得现金;dp[i][1] 表示第i天不持有股票所得最多现金

  • 递推公式

在121.买卖股票的最佳时机中,由于股票全程只能买卖一次,所以如果买入股票,那么第i天持有股票即dp[i][0]一定就是 -prices[i]

本题,因为一只股票可以买卖多次,所以当第i天买入股票的时候,所持有的现金可能有之前买卖过的利润


接下来开始讨论核心代码:

那么如果第i天持有股票,如果是在第i天买入的,那么所得现金就是昨天不持有股票的现金再减去今天股票的价格,所以dp[i - 1][1] - prices[i]

如果第i天不持有股票即dp[i][1]

  1. i-1天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 即:dp[i - 1][1]
  2. i天卖出股票,所得现金就是按照今天股票价格卖出后所得现金即:prices[i] + dp[i - 1][0]

综上所述:递推公式为

            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]); // 注意这里是和121. 买卖股票的最佳时机唯一不同的地方。dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]);

CPP代码

这里仅给出滚动数组版本的代码( 只记录当前天的dp状态和前一天的dp状态

class Solution {
public:int maxProfit(vector<int>& prices) {int len = prices.size();vector<vector<int>> dp(2, vector<int>(2)); // 注意这里只开辟了一个2 * 2大小的二维数组dp[0][0] -= prices[0];dp[0][1] = 0;for (int i = 1; i < len; i++) {dp[i % 2][0] = max(dp[(i - 1) % 2][0], dp[(i - 1) % 2][1] - prices[i]);dp[i % 2][1] = max(dp[(i - 1) % 2][1], prices[i] + dp[(i - 1) % 2][0]);}return dp[(len - 1) % 2][1];}
};

123.买卖股票的最佳时机III

力扣题目链接

文章链接:123.买卖股票的最佳时机III

视频链接:动态规划,股票至多买卖两次,怎么求? | LeetCode:123.买卖股票最佳时机III

状态:看到困难吓我一跳

本题有又变套路了,题目中谈到,至多买卖两次,这就意味着可以买卖一次、可以买卖两次、也可以不买卖。

但其实最本质的无非就是要设置的状态多多了,之前我们也就两个状态,持有和不持有

思路

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

现在,我们状态比之前多多了:

  1. 没有操作 (其实我们也可以不设置这个状态)
  2. 第一次持有股票
  3. 第一次不持有股票
  4. 第二次持有股票
  5. 第二次不持有股票

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

  • 确定递推公式
  1. 我们确定dp[i][1]的状态
    在这里插入图片描述

我们应该从两种情况里选择最大的,即dp[i][1]=max(dp[i-1][0]=prices[i], dp[i-1][1])

  1. 确定dp[i][2]的状态

在这里插入图片描述

同理dp[i][2]=max(dp[i-1][1] + prices[i], do[i-1][2])

3.确定dp[i][3]的状态

在这里插入图片描述

同理dp[i][3]=max(dp[i-1][2] + prices[i], do[i-1][3])

  1. 确定dp[i][4]的状态

在这里插入图片描述

同理dp[i][4]=max(dp[i-1][3] + prices[i], do[i-1][4])

  • dp数组的初始化

首先,我们只用初始化第0天,因为从此之后的n天都是由前一天初始化来的。

然后,dp[0][0]显然是等于0的,

每次的买入操作应当初始化为-prices[0],因为买入我们本次的钱肯定就是负数了,至于第二次买入可以理解为我们第零天先买入,再卖出,然后再买入

卖出操作应该初始化为0,因为就算再同一天买入卖出收获的钱肯定是0

vector<vector<int>> dp(prices.size(), vector<int>(5, 0));
dp[0][1] = -prices[0];
dp[0][3] = -prices[0];
  • 确定遍历顺序

跟之前的一样,从左到右即可

  • 举例推导dp数组

以输入[1,2,3,4,5]为例

20201228181724295-20230310134201291

我们最终的最大利润肯定是出现在最后一天的第二次dp[4][4]

CPP代码

class Solution {
public:int maxProfit(vector<int>& prices) {if (prices.size() == 0) return 0;vector<vector<int>> dp(prices.size(), vector<int>(5, 0));dp[0][1] = -prices[0];dp[0][3] = -prices[0];for (int i = 1; i < prices.size(); i++) {dp[i][0] = dp[i - 1][0];dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] + prices[i]);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]);}return dp[prices.size() - 1][4];}
};//空间优化(滚动数组)
class Solution {
public:int maxProfit(vector<int>& prices) {if (prices.size() == 0) return 0;vector<int> dp(5, 0);dp[1] = -prices[0];dp[3] = -prices[0];for (int i = 1; i < prices.size(); i++) {dp[1] = max(dp[1], dp[0] - prices[i]);dp[2] = max(dp[2], dp[1] + prices[i]);dp[3] = max(dp[3], dp[2] - prices[i]);dp[4] = max(dp[4], dp[3] + prices[i]);}return dp[4];}
};

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

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

相关文章

【C++】详解STL容器之一的 vector

目录 概述 迭代器 数据结构 优点和缺点 接口介绍 begin end rbegin rend resize reseve insert erase 其他一些接口 模拟实现 框架 获取迭代器 深浅拷贝 赋值重载 reseve resize 拷贝构造 构造 析构 insert erase 其他 概述 vector是STL的容器之一。…

如何避免在抓取Google时被屏蔽?代理IP的7个使用误区

在当今数字化时代&#xff0c;数据采集和网络爬取已成为许多企业和个人必不可少的业务活动。对于爬取搜索引擎数据&#xff0c;特别是Google&#xff0c;使用代理IP是常见的手段。然而&#xff0c;使用代理抓取Google并不是一件轻松的事情&#xff0c;有许多常见的误区可能会导…

C++新特性-线程

主要内容 thread、condition、mutexatomicfunction、bind使用新特性实现线程池&#xff08;支持可变参数列表&#xff09;异常协程其他 1 C11多线程thread 重点&#xff1a; join和detach的使用场景thread构造函数参数绑定c函数绑定类函数线程封装基础类互斥锁mutexconditi…

sql 中having和where区别

where 是用于筛选表中满足条件的行&#xff0c;不可以和聚类函数一起使用 having 是用于筛选满足条件的组 &#xff0c;可与聚合函数一起使用 所以having语句中不能使用select中定义的名字

程序员有什么实用神器?

程序员的实用神器 在软件开发的海洋中&#xff0c;程序员的实用神器如同航海中的指南针&#xff0c;帮助他们导航、加速开发、优化代码质量&#xff0c;并最终抵达成功的彼岸。这些工具覆盖了从代码编写、版本控制到测试和部署的各个环节。 程序员常用的一些神器包括&#xf…

Python数据分析之绘制相关性热力图的完整教程

前言 文章将介绍如何使用Python中的Pandas和Seaborn库来读取数据、计算相关系数矩阵&#xff0c;并绘制出直观、易于理解的热力图。我们将逐步介绍代码的编写和执行过程&#xff0c;并提供详细的解释和示例&#xff0c;以便读者能够轻松地跟随和理解。 大家记得需要准备以下条…

Python实现Chiikawa

写在前面 哈&#xff1f;呀哈&#xff01;本期小编给大家素描版Chiikawa&#xff01; 主人公当然是我们可爱的吉伊、小八以及乌萨奇啦~ Chiikawa小小可爱 《Chiikawa》是一部来自日本的超萌治愈系漫画与动画作品&#xff0c;由作者秋田祯信创作。"Chiikawa"这个名字…

c 双向链表

图片 #include <stdio.h> #include <stdlib.h> #include <string.h>int main(void){ struct film{char name[20];int id;struct film *pre; //前向指针struct film *next; //后向指针 };struct film *headNULL;struct film *ls,*lspre,*work;in…

张大哥笔记:如果不想继续打工,互联网创业或许是最好的出路!

互联网时代最好的出路&#xff0c;就是选择创业&#xff0c;不要选择打工。选择打工很亏&#xff0c;你学到的是打工的本事。而创业&#xff0c;看似不赚钱&#xff0c;看似倒霉&#xff0c;但是会锻炼出了你一天赚几千&#xff0c;甚至几万的本事。 随着互联网越来越被人们所…

Kompas AI图片转换器:高效解决格式不兼容问题

最新Kompas AI&#xff1a;一键转换图片格式&#xff0c;提升工作效率 在数字化的世界里&#xff0c;图片已成为我们交流和分享信息不可或缺的媒介。然而&#xff0c;不同的场景往往需要不同格式的图片&#xff0c;这时&#xff0c;一个高效的图片格式转换工具就显得尤为关键。…

1553B总线接口仿真卡,1553B IP核,适用于航空机载,飞机综合航电等领域

1553B总线接口卡可作为通讯或仿真测试板卡使用&#xff0c;支持USB&#xff0c;PCI&#xff0c;PXI&#xff0c;CPCI&#xff0c;以太网&#xff0c;RS422&#xff0c;RS485等计算机总线平台&#xff0c;单功能&#xff08;1个BC、0-31个RT和1个BM&#xff0c;当前仅可单工作模…

安卓surfaceview的使用方式

1. 什么是surfaceview surfaceview内部机制和外部层次结构 在安卓开发中&#xff0c;我们经常会遇到一些需要高性能、高帧率、高画质的应用场景&#xff0c;例如视频播放、游戏开发、相机预览等。这些场景中&#xff0c;我们需要直接操作图像数据&#xff0c;并且实时地显示到…

win10安装.NET Framework 3.5(包括.net2.0和3.0)

打开控制面板 选择”程序” 点击”启用或关闭Windows功能“ 把.NET Framework 3.5选项勾选即可&#xff0c;若没有下载的&#xff0c;下载即可。 PS:如果下载过程出错&#xff0c;按如下流程&#xff1a; 右击”此电脑”选择“管理”&#xff0c;找到“服务和应用程序”&#x…

揭秘全网热门话题:抖音快速涨粉方法,巨量千川投流助你日增10000粉

在当今社交媒体的时代( 千川投流&#xff1a;hzzxar&#xff09;抖音成为了年轻人分享自己才华和生活的平台。然而&#xff0c;要在抖音上快速获得关注和粉丝&#xff0c;却不是一件容易的事情。今天&#xff0c;我们将揭秘全网都在搜索的抖音快速涨1000粉的秘籍&#xff0c;带…

【嵌入式系统复习总结】第四章 汇编程序设计

文章目录 前情提要第四章 汇编程序设计1. 伪操作的含义&#xff0c;了解几个常用的&#xff1a;GBLA、GBLL 和 GBLS&#xff0c;LCLA、LCLL 和 LCLS&#xff0c;SETA、SETL、SETS&#xff0c;数据定义伪操作&#xff1a;DCB、DCW、DCD&#xff0c;其他常用 伪操作&#xff08;A…

【OceanBase 系列】—— OceanBase v4.3 特性解读:查询性能提升之利器列存储引擎

原文链接&#xff1a;OceanBase 社区 对于分析类查询&#xff0c;列存可以极大地提升查询性能&#xff0c;也是 OceanBase 做好 HTAP 和 OLAP 的一项不可缺少的特性。本文介绍 OceanBase 列存的实现特色。 OceanBase从诞生起就一直坚持LSM-Tree架构&#xff0c;不断打磨功能支…

基于卷积神经网络的信号解卷积(简单版,MATLAB)

简单演示一下基于卷积神经网络的信号解卷积&#xff0c;有个大致印象即可。 构造卷积滤波器 r 0.9; % Define filter om 0.95; a [1 -2*r*cos(om) r^2]; b [1 r*cos(om)]; h filter(b, a, [zeros(1,38) 1 zeros(1,40)]); N 500; K 25; sigma 1; 绘制输入信号分量 s…

2024首届香港多元文化暨人工智能国际旗袍选美比赛在香港启动

4月30日&#xff0c;2024首届香港多元文化暨人工智能国际旗袍选美比赛在香港帝京酒店正式启动&#xff0c;本次是英雄电影娱乐有限公司创新的旗袍文化选美项目。除了旗袍文化选美&#xff0c;还有中国悠久的“香道文化和茶道文化”融合一起&#xff0c;将中国的多元文化与旗袍文…

类和对象-Python-第一部分

初识对象 使用对象组织数据 class Student:nameNonegenderNonenationalityNonenative_placeNoneageNonestu_1Student()stu_1.name"林军杰" stu_1.gender"男" stu_1.nationality"中国" stu_1.native_place"山东" stu_1.age31print(stu…

自主实现Telnet流量抓取

自主实现Telnet流量抓取 根据测试需求&#xff0c;需要抓取Telnet流量包&#xff0c;使用wireshark Python&#xff08;socket、telnetlib库&#xff09;实现 实现代码 主要此处有坑&#xff0c; 根据协议规则&#xff0c;wireshark 默认端口为23 的是Telnet协议&#xff0…