动态规划之买卖股票大集合

news2024/11/18 13:31:30

目录

引言

1.只能进行一次买卖股票(最多只能买一股股票)

2.可以进行多次股票买卖,且没有手续费(最多只能买一股股票)

3.可以进行多次股票买卖,但是有冷冻期,无手续费(最多只能买一股股票)

4.可以进行多次股票买卖,但是有手续费(最多只能买一股股票)


引言

作为动态规划中最常见的一类问题,买卖股票问题的思想也时常会出现在动态规划的题目中,买卖股票主要分为两大类,一种是有限制条件的,另一种是没有限制条件的

买卖股票问题主要的思路是用一个二维dp数组去存储是否持有股票的两个状态

比如说dp[ i ][ 0 ]表示就的就是在第i天持有股票的最大金额

dp[ i ][ 1 ]表示的就是在第i天没有持有股票的最大金额

然后我们就可以写出递推关系式

例如对于

(1)只能买一次股票来说

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

对于持有股票来说,由于只能购买一次,所以对于购买股票的时候,初始金额一定为0,因此我们的持有的状态只能由前一天持有的最小花费的状态和本天购买的花费的较小值推出来

不持有的状态是由前一天包括之前卖出股票的最大价值和在本天卖出股票的价值的较大者推出

(2)可以买卖多次股票

唯一的不同点在于购买的时候,因为可以买卖多次,因为购买股票的初始金额必然是有可能为非0的因此,我们要通过前一天包括之前不持有股票的状态推出今天持有股票的最大状态

dp[i][0]=max(dp[i-1][0],dp[i-1][1]-p[i]);//唯一不同点

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

当然了,这边的二维数组也可以将空间压缩成1维dp数组,让其变成一个滚动数组,从而降低空间复杂度

dp[ 0 ]指的就是持有股票的状态

dp[ 1 ]指的就是不持有股票的状态

1.只能进行一次买卖股票(最多只能买一股股票)

只能买卖一次 持有状态 不能由之前不持有的利润累加,就是持有状态永远都是0减去今天的价格

来看一道例题

传送门——买卖股票的最佳时机

题解:很标准的买卖股票问题,只能买卖一次,因此我们就可以用动规五部曲去完成这道题

1.明确dp数组的含义,首先就是dp[ i ][ 0 ]表示的是 对于第i天来说,持有股票的最大金额

dp[ i ][ 1 ]表示的是 对于第i天来说,不持有股票的最大金额

 2.状态转移方程:dp[i][0]=max(dp[i-1][0],-p[i]);   
dp[i][1]=max(dp[i-1][1],dp[i-1][0]+p[i]);

3.初始化dp[1][0]=-p[1]//p[1]指的是第p天股票的价值,dp[1][1]=0;

4.遍历顺序,第一天遍历到第n天就行

二维dp数组:

#include<bits/stdc++.h>
using namespace std;

int n;
int p[105];
int dp[105][2];
//dp数组的含义
//dp[i][0]表示的是在第i天拥有股票的最大价值,可以是在第i天买的股票,也可以是在之前买的
//说白了dp[i][0]统计的就是在第i天及之前,购进股票的最小花费 
//dp[i][1]表示的是在第i天没有股票的最大价值,既可以是没有买,也可以是卖了又买了
//这个用于统计的就是买卖股票的最大价值 
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>p[i];
	dp[1][0]=-p[1];//在第一天拥有股票的最大价值 
	dp[1][1]=0;//在第一天没有拥有股票的最大价值
	
	for(int i=2;i<=n;i++)
	{
		dp[i][0]=max(dp[i-1][0],-p[i]);
		dp[i][1]=max(dp[i-1][1],dp[i-1][0]+p[i]);
	}
	cout<<dp[n][0]<<"\n";
	 cout<<dp[n][1];
	return 0;
}

一维dp数组: 

//一维dp数组
#include<bits/stdc++.h>
using namespace std;
int n;
int p[105];
int dp[2];//dp[0]表示持有股票的状态,dp[1]指的是没持有股票的状态
 
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>p[i];
	}
	dp[0]=-p[1];
	dp[1]=0;
	for(int i=1;i<=n;i++)
	{
		dp[0]=max(dp[0],-p[i]);
		
		dp[1]=max(dp[1],dp[0]+p[i]);
	}
	cout<<dp[1];
	return 0;
 } 

2.可以进行多次股票买卖,且没有手续费(最多只能买一股股票)

传送门——买卖股票的最佳时机2

题解:也是很经典的股票买卖问题,并且是可以买卖多次,且不需要手续费的,唯一和·上面不同的就是去推不持有股票的状态发生了一些变化,其他的一样,包括dp数组的含义啊,遍历顺序啊,初始化啊,什么的,都是一样的

二维dp数组:

#include<bits/stdc++.h>
using namespace std;
int n;
int p[105];
int dp[105][2];

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>p[i];
	dp[1][0]=-p[1];
	dp[1][1]=0;
	
	for(int i=2;i<=n;i++)
	{
		dp[i][0]=max(dp[i-1][0],dp[i-1][1]-p[i]);//唯一不同点
		//因为原来只能购买一次,所以计算最大的肯定是-p[i],但是现在可以买卖多次,就说明初始值不一定为0,我们的初始值为dp[i-1][1]的值 
		dp[i][1]=max(dp[i-1][1],dp[i-1][0]+p[i]);
	}
	cout<<dp[n][1];
	return 0;
}

 一维的dp数组:

#include<bits/stdc++.h>
using namespace std;
int n;
int p[105];
int dp[2];//dp[0]持有股票,dp[1]不持有股票 

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>p[i];
	dp[0]=-p[1];
	dp[1]=0;
	for(int i=1;i<=n;i++)
	{
		dp[1]=max(dp[1],dp[0]+p[i]);
		dp[0]=max(dp[0],dp[1]-p[i]);
	}
	cout<<dp[1];
	return 0;
}

3.可以进行多次股票买卖,但是有冷冻期,无手续费(最多只能买一股股票)

这个相比于正常股票买卖问题在不持股状态分的更加细致,对于不持股状态可以分为,因为卖出的冷冻期导致不持股,或者是不是冷冻期导致的不持股,再算上持股状态,因此总共有三个状态,我们可以将其列举出来

0:持股状态

1:不是因为冷冻期而导致的不持股

2:因为冷冻期而导致的不持股

分别写出各自的状态转移方程

对于持股状态来说,他只能由之前的持股状态不是冷冻期的不持股,买第i天的股票转移过来

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

对于不是因为冷冻期而导致的不持股来说,他只能由之前的非冷冻期不持股冷冻期不持股推出来

(因为一旦卖出就要进入冷冻期,没办法由0推出1)

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

对于因为冷冻期而导致的不持股来说,他只能由之前的持股状态卖出得到

dp[i][2]=dp[i-1][0]+p[i]; 

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

#include<bits/stdc++.h>
using namespace std;
int n;
int p[105];
int dp[105][3];
//0:持股状态
//1:不是因为卖出股票而导致的不持股 
//2:因为卖出股票而导致的不持股 

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>p[i];
	dp[1][0]=-p[1];
	dp[1][1]=0;
	dp[1][2]=0;//第一天肯定不能是冷冻期,必然是0 
	for(int i=2;i<=n;i++)
	{
		dp[i][0]=max(dp[i-1][0],dp[i-1][1]-p[i]);
		dp[i][1]=max(dp[i-1][1],dp[i-1][2]);
		dp[i][2]=dp[i-1][0]+p[i]; 
	}
	cout<<max(dp[n][1],dp[n][2]);
	return 0;
}

4.可以进行多次股票买卖,但是有手续费(最多只能买一股股票)

这个只需要在dp[1]的地方改一下即可,就是在获取到赚的钱的时候顺带减一下手续费就ok,难度比第三个低很多

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

题解:和第二个差不多,只不过多加了个手续费,状态转移方程变为dp[1]=max(dp[1],dp[0]+p[i]-fee);

#include<bits/stdc++.h>
using namespace std;
int n;
int p[105];
int dp[2];//dp[0]持有股票,dp[1]不持有股票 

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>p[i];
	int fee=0;
	cin>>fee;
	dp[0]=-p[1];
	dp[1]=0;
	for(int i=1;i<=n;i++)
	{
		dp[1]=max(dp[1],dp[0]+p[i]-fee);
		dp[0]=max(dp[0],dp[1]-p[i]);
	}
	cout<<dp[1];
	return 0;
}

 

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

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

相关文章

Firefox浏览器网页上的按钮点击无效解决办法

我在github下点下载经常不好使&#xff0c;查了原因&#xff0c;原来是浏览器的问题。在Firefox浏览器的设置里面&#xff0c;去掉一些cookies的禁用即可。之后&#xff0c;就可以点击按钮成功响应了。

智能跳绳的产品体验与思考(一)

我&#xff0c;虽称不上跳绳高手&#xff0c;却对这项运动怀有深厚的热爱&#xff0c;也曾在某电商平台上选购过一款智能跳绳&#xff0c;希望能借此提升我的跳绳技巧。今天&#xff0c;咱们就来聊聊我和这条绳子的发生的一些故事&#xff0c;外加我的一些思考。 此刻&#xf…

NDIS协议驱动(四)

NDIS 定义对象标识符 (OID) 值&#xff0c;以标识适配器参数&#xff0c;其中包括设备特征、可配置设置和统计信息等操作参数。 协议驱动程序可以查询或设置基础驱动程序的操作参数。 NDIS 还为 NDIS 6.1 及更高版本的协议驱动程序提供直接 OID 请求接口。 直接 OID 请求路径支…

Java-文件操作

一、创建文件 1.创建文件夹 创建文件夹时&#xff0c;注意两个条件&#xff0c;该路径对应的是否为目录&#xff08;dir&#xff09;&#xff0c;该文件夹是否存在。 File Apathnew File("./文件夹A"); //当前路径文件夹的存储路径if(!Apath.exists() &&am…

【研0深度学习】李宏毅2024春《生成式人工智能导论》持续更新...

文章目录 第1讲 什么是生成式人工智慧&#xff1f;第2讲 今日的生成式人工智慧厉害在哪里&#xff1f;第3-5讲 训练不了人工智慧&#xff0c;你可以训练你自己&#xff08;在不训练模型的情况下强化语言模型的方法&#xff09;第6讲 大模型修炼史——第一阶段 自我学习 累计实力…

ROS2入门21讲__第08讲__话题:节点间传递数据的桥梁

目录 前言 通信模型 发布/订阅模型 多对多通信 异步通信 消息接口 案例一&#xff1a;Hello World话题通信 运行效果 发布者代码解析 程序实现 流程总结 订阅者代码解析 程序实现 流程总结 案例二&#xff1a;机器视觉识别 运行效果 发布者代码解析 订阅者代…

WebGL学习(一)渲染关系

学习webgl 开发理解渲染关系是必须的&#xff0c;也非常重要&#xff0c;很多人忽视了这个过程。 我这里先简单写一下&#xff0c;后面尽量用通俗易懂的方式&#xff0c;举例讲解。 WebGL&#xff0c;全称Web Graphics Library&#xff0c;是一种在网页上渲染3D图形的技术。它…

FPGA时钟:驱动数字逻辑的核心

一、引言 在FPGA&#xff08;现场可编程门阵列&#xff09;设计中&#xff0c;时钟信号是不可或缺的关键要素。时钟信号作为时序逻辑的心跳&#xff0c;推动着FPGA内部各个存储单元的数据流转。无论是实现复杂的逻辑运算还是处理高速数据流&#xff0c;都需要精确的时钟信号来保…

CASS11自定义宗地图框

1、找到CASS11的安装路径&#xff0c;找到如下文件夹&#xff1a; 2、打开【report】文件夹&#xff0c;如下&#xff1a; 3、打开其中一个压缩包&#xff0c;如【标准宗地图】压缩包&#xff0c;结果如下&#xff1a; 4、打开后&#xff0c;将其另存为到桌面&#xff0c;随后关…

Leetcode621. 任务调度器

Every day a Leetcode 题目来源&#xff1a;621. 任务调度器 类似题目&#xff1a;1953. 你可以工作的最大周数 解法1&#xff1a;贪心 本质上来说&#xff0c;我们需要构造一个尽量短的&#xff0c;相同元素间隔 > (n1) 的序列。 用一个数组 cnt 统计每个任务的次数。…

Oracle创建用户时提示ORA-65096:公用用户名或角色名无效

Oracle创建用户时提示“ORA-65096&#xff1a;公用用户名或角色名无效” 如下图所示&#xff1a; 解决方法&#xff1a;在新增用户名前面加上C##或者c##就可以解决无效问题&#xff0c;具体什么原因还不清楚&#xff0c;需要再研究一下。

Discourse 安装后安全配置考虑

防火墙 防火墙是肯定要装机器上的&#xff0c;并且端口只开放了 443 和 22。 22 的端口还只限制了部分 IP 段的访问&#xff0c;通常只允许给内部网络的 SSH。 Web 服务应该只走 443&#xff0c;80 端口的做好自动重定向到 443。 CloudFlare 可以用一个 CloudFlare 的负载…

行为设计模式之状态模式

文章目录 概述定义结构图 2.代码示例小结 概述 定义 状态模式(state pattern)的定义: 允许一个对象在其内部状态改变时改变它的行为。 对象看起来似乎修改了它的类。 状态模式就是用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题.。状态模式将一个对象的状态…

QtCreator调试运行工程报错,无法找到相关库的的解决方案

最新在使用国产化平台做qt应用开发时&#xff0c;总是遇到qtcreator内调试运行 找不到动态库的问题&#xff0c;为什么会出现这种问题呢&#xff1f;明明编译的时候能够正常通过&#xff0c;运行或者调试的时候找不到相关的库呢&#xff1f;先说结论&#xff0c;排除库本身的问…

基于tensorflow的咖啡豆识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 一、前期工作 1. 设置GPU import tensorflow as tfgpus tf.config.list_physical_devices("GPU")if gpus:tf.config.experimental.set_memory_gr…

远程桌面连接--“发生身份验证错误。要求的函数不受支持”

出现身份验证错误 要求的函数不受支持的问题&#xff0c;可以通过以下几种方法尝试解决&#xff1a;12 对于Windows 10家庭版用户&#xff0c;需要修改注册表信息。具体步骤如下&#xff1a; 按下WIN R&#xff0c;输入regedit&#xff0c;点击确定&#xff0c;打开注册表编辑…

openresty(Nginx) 隐藏 软包名称及版本号 升级版本

1 访问错误或者异常的URL 2 修改配置&#xff0c;重新编译&#xff0c;升级 #修改版本等 vim ./bundle/nginx-1.13.6/src/core/nginx.h #define nginx_version 1013006 #define NGINX_VERSION "1.13.6" #define NGINX_VER "openresty/&q…

python中的-1是什么意思

python中的-1是什么意思&#xff1f; -1指的是索引&#xff0c;即列表的最后一个元素。 比如你输入一个列表&#xff1a; a &#xff1d; [1,2,3,4,5,6,7] a[-1]就代表索引该列表最后一个值&#xff0c;你可以 b a[-1] print(b) 结果如下&#xff1a; 7 索引从左往右是…

5.28学习总结

java复习总结 hashcode()和equals() hashcode():在Object里这个方法是通过返回地址的整数值来生成哈希值。 equals():在Object里这个方法是通过比较他们的内存地址来确定两个对象是否相同。 运行效率&#xff1a;hashcode的时间复杂度为O(1)&#xff08;因为只要计算一次哈…

SpringCloud之SSO单点登录-基于Gateway和OAuth2的跨系统统一认证和鉴权详解

单点登录&#xff08;SSO&#xff09;是一种身份验证过程&#xff0c;允许用户通过一次登录访问多个系统。本文将深入解析单点登录的原理&#xff0c;并详细介绍如何在Spring Cloud环境中实现单点登录。通过具体的架构图和代码示例&#xff0c;我们将展示SSO的工作机制和优势&a…