当前位置: 首页 > news >正文

跟着Carl学算法--动态规划【5】

买卖股票的最佳时机

力扣链接:买卖股票的最佳时机

题目:给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0

思路

从上一题开始,每一个结点都有了多个状态

这里,今天的这个”结点“获得最大收益的有两种状态:今天持有股票或者今天不持有股票的最大收益,都取决于前一天的持有股票或不持有股票的最大收益。这也是之后股票模板题的套路

  • dp[i][1/0]代表第i天持有或者不持有股票的最大收益,为了对应股价数组,天数i也从0开始计数

  • 递推式

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

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

    今天不持有股票可能是昨天就不持有股票继承下来的,或者昨天持有股票今天出售了导致的,所以今天不持有股票的最大收益是昨天不持股票的最大收益昨天持有股票的最大收益加上今天出售股票的收益的最大值

    同理,今天持有股票可能是昨天就持有股票继承下来的,或者昨天不持有股票今天买入了导致的,所以今天持有股票的最大收益是昨天持股票的最大收益昨天不持有股票的最大收益减去今天购买股票的投入的最大值,注意因为此题只能买一次,所以昨天不持有股票的最大收益就是0

  • 初始化:初始dp[0][0]=0和dp[0][1]=-prices[0];

class Solution {
public:int maxProfit(vector<int>& prices) {vector<vector<int>> dp(prices.size(), vector(2, 0));// 0代表不持有,1代表持有dp[0][0] = 0;dp[0][1] = -prices[0];for (int i = 1; i < prices.size(); i++) {dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);dp[i][1] = max(dp[i - 1][1], 0 - prices[i]);}return max(dp[prices.size() - 1][0], dp[prices.size() - 1][1]);}
};

仔细想想,如果持有股票只有一种情况,对于任意一天,其实肯定是未持有股票收益高于持有股票的,最后返回未持有股票的情况即可,事实证明也是如此。


买卖股票的最佳时机II

力扣链接:买卖股票的最佳时机II

题目:给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润

思路

与上一题的唯一区别,就是可以多买多卖,只需要改变持有递推式的买入部分即可

  • dp[i][1] = max(dp[i - 1][1], 0 - prices[i]);改为dp[i][1] = max(dp[i - 1][1], dp[i-1][0] - prices[i]);,前一天未持有股票的最大收益因为多买多卖,不再是固定的0了。
class Solution {
public:int maxProfit(vector<int>& prices) {vector<vector<int>> dp(prices.size(), vector(2, 0));// 0代表不持有,1代表持有dp[0][0] = 0;dp[0][1] = -prices[0];for (int i = 1; i < prices.size(); i++) {dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);}return max(dp[prices.size() - 1][0], dp[prices.size() - 1][1]);}
};

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

力扣链接:买卖股票的最佳时机含手续费

题目:给定一个整数数组 prices,其中 prices[i]表示第 i 天的股票价格 ;整数 fee 代表了交易股票的手续费用。

你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。

返回获得利润的最大值。

注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。

思路

与上一题的区别,就是卖出时要减去手续费即可,只需要改变未持有递推式的卖出部分即可

  • dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);改为dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]-fee);
class Solution {
public:int maxProfit(vector<int>& prices,int fee) {vector<vector<int>> dp(prices.size(), vector(2, 0));// 0代表不持有,1代表持有dp[0][0] = 0;dp[0][1] = -prices[0];for (int i = 1; i < prices.size(); i++) {dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee);dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);}return max(dp[prices.size() - 1][0], dp[prices.size() - 1][1]);}
};

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

力扣链接:买卖股票的最佳时机含冷冻期

题目:给定一个整数数组prices,其中第 prices[i] 表示第 *i* 天的股票价格 。

设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):

  • 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。

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

思路

与买卖股票II的区别,就是卖出以后会有冷冻期一天,不能买入,也就是说买入会受到影响,所以只要改变持有递推式的买入部分就可以了

  • dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);改为dp[i][1] = max(dp[i - 1][1], dp[i - 2][0] - prices[i]);因为买入时,要确保今天不是冷冻期,仅对前一天状态进行约束是不行的,前一天未持有,也可能是卖出去了,那今天就是冷动期了,至少得对前两天就进行约束,即前两天就未持有了,就算前两天卖出了,到今天也刚好冷冻期过了,
  • 同时,因为递推式中出现了i-2,所以初始化时,就需要对前两项进行初始化,同时也要判断给出的股票数是否大于1。
class Solution {
public:int maxProfit(vector<int>& prices) {if (prices.size() == 1)return 0;vector<vector<int>> dp(prices.size(), vector(2, 0));dp[0][0] = 0;dp[0][1] = -prices[0];dp[1][1] = max(dp[0][1], dp[0][0] - prices[1]);dp[1][0] = max(dp[0][0], dp[0][1] + prices[1]);for (int i = 2; i < prices.size(); i++) {dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);dp[i][1] = max(dp[i - 1][1], dp[i - 2][0] - prices[i]);}return max(dp[prices.size() - 1][0], dp[prices.size() - 1][1]);}
};

买卖股票的最佳时机III

力扣链接:买卖股票的最佳时机III

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

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

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

思路

与买卖股票II类似,但是至多买卖股票数不能超过两次,如何确保不会超过两次?

可以进一步细分状态,将持有细化为持有第一次和第二次,未持有细化为未持有第一次和未持有第二次,再额外增加以一个未操作,来标记第一次买入前的状态,这样每一个状态就都包含了,

  • dp[i][0/1/2/3/4],分别代表未操作,第一次持有。。。。第二次未持有
  • 初始化:第0天所有未持有的状态都是0,持有的都是-prices[0]
  • 递推式:要么继承前一天的同一个状态,要么取决于前一天的上一个状态。这里每一天的未操作状态始终为0,不需要递推更新
class Solution {
public:int maxProfit(vector<int>& prices) {vector<vector<int>> dp(prices.size(), vector(5, 0));dp[0][0] = 0;dp[0][1] = -prices[0];dp[0][2] = 0;dp[0][3] = -prices[0];dp[0][4] = 0;for (int i = 1; i < prices.size(); i++) {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 max(dp[prices.size() - 1][2], dp[prices.size() - 1][4]);}
};

买卖股票的最佳时机IV

力扣链接:买卖股票的最佳时机IV

题目:给你一个整数数组 prices 和一个整数 k ,其中 prices[i] 是某支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。也就是说,你最多可以买 k 次,卖 k 次。

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

思路

相较于上一题,明确的至多两次买卖改为了不确定的k次,思路与递推式都与III相同,只要将III抽象成模板即可。

  • dp[i][0/.../2*k]:分别代表未操作、第一次持有。。。。第k次未持有,至多k次买卖,一次买卖需要2个状态,再加上未操作,一共2*k+1个状态。

  • 初始化:对第0天的状态%2,偶数的都是未持有,奇数的都是持有,未持有即为0,持有即为-prices[0]

  • 递推式:未操作不进行递推

     if (j % 2 == 1) //奇数代表持有,如果今天买入,那就是前一天本次未持有最大收益-今天股票价格dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - 1] - prices[i]);
    else			//偶数代表未持有,如果今天卖出,那就是前一天上一次持有最大收益+今天股票价格dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - 1] + prices[i]);
    

    今天的某个状态j,要么继承前一天的同一个状态,要么取决于前一天的上一个状态。

class Solution {
public:int maxProfit(int k, vector<int>& prices) {int state = 2 * k + 1;vector<vector<int>> dp(prices.size(), vector(state, 0));for (int i = 0; i < state; i++) {if (i % 2 == 1)dp[0][i] = -prices[0];}for (int i = 1; i < prices.size(); i++) {for (int j = 1; j < state; j++) // 偶数代表不持有,奇数代表持有if (j % 2 == 1)dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - 1] - prices[i]);elsedp[i][j] = max(dp[i - 1][j], dp[i - 1][j - 1] + prices[i]);}int maxp = 0;for (int i = 2; i < state; i += 2)maxp = max(dp[prices.size() - 1][i - 2], dp[prices.size() - 1][i]);return maxp;}
};

文章转载自:

http://0CZR8vqC.gtxrw.cn
http://u7J1Ls6A.gtxrw.cn
http://8PEVTkSN.gtxrw.cn
http://RNccjyOK.gtxrw.cn
http://ELpr6A4q.gtxrw.cn
http://adrlunVR.gtxrw.cn
http://eiFjWFDN.gtxrw.cn
http://Rcot3DBU.gtxrw.cn
http://XzVSvFTo.gtxrw.cn
http://AemWkm0M.gtxrw.cn
http://dV6nH2Zr.gtxrw.cn
http://bC19XuXH.gtxrw.cn
http://rViiBq4z.gtxrw.cn
http://woab0mfu.gtxrw.cn
http://B7kmLyDX.gtxrw.cn
http://SseN9z17.gtxrw.cn
http://E2Vd4ZO0.gtxrw.cn
http://TxqJUDkm.gtxrw.cn
http://q9AeRG7A.gtxrw.cn
http://ZKBPsS2N.gtxrw.cn
http://V88rDGaX.gtxrw.cn
http://84Zsh5xO.gtxrw.cn
http://JaxgcvIa.gtxrw.cn
http://SnJWTQoc.gtxrw.cn
http://hUvNZEdo.gtxrw.cn
http://TJ2PQWoO.gtxrw.cn
http://7aUUeZQS.gtxrw.cn
http://E9MO0l2w.gtxrw.cn
http://sLXZG9B5.gtxrw.cn
http://Z3IuyDHQ.gtxrw.cn
http://www.dtcms.com/a/382785.html

相关文章:

  • 一种基于因果干预的少样本学习的故障诊断模型
  • Go并发编程实战:深入理解Goroutine与Channel
  • 嵌入式硬件设计
  • (附源码)基于Spring Boot社区“邻里帮”平台的设计与实现
  • 贪心算法java
  • AI问答-Nuxt4:什么时候发布的,有哪些特性,和Nuxt3相比 有哪些优势 / Nuxt4 / Nuxt-v4
  • MyBatis 从入门到精通(第三篇)—— 动态 SQL、关联查询与查询缓存
  • 10 C++map/set的底层数据结构红黑树它来了,红黑树入门全解。
  • 【iOS】ViewController的生命周期
  • 数据库基础-01
  • 免费无版权!PPT图标素材的6个优质获取渠道
  • 【STL库】map/set 的封装原理
  • 市面上各类USB无线抓包网卡测试与收录(握手包抓包/无线监听)
  • 基于bang-bang起停式算法的交流电机FOC控制系统simulink建模与模拟仿真
  • 使用HTTPS 服务在浏览器端使用摄像头的方式解析
  • AI 机器视觉检测方案:破解食物包装四大质检难题,筑牢食品安全防线
  • Science Advances--3D打印生物启发扭曲双曲超材料,用于无人机冲击缓冲和自供电实时传感
  • HarmonyOS生态开发核心工具技术介绍及关于CSDN增加ArkTS等标签建议
  • 【算法笔记】堆和堆排序
  • 电商导购系统的微服务监控体系:基于Prometheus与Grafana的可视化方案
  • fMoE论文阅读笔记
  • 721SJBH笔记本电脑销售网站
  • k3s集群部署(使用外部etcd集群)
  • 京东返利app的分布式ID生成策略:雪花算法在订单系统中的实践
  • 大数据分析岗位发展前景与行业需求分析
  • 【Linux手册】共享内存:零拷贝实现共享的优势与实操指南
  • ARM的TrustZone
  • 返利app排行榜的缓存更新策略:基于过期时间与主动更新的混合方案
  • springboot+zookeeper+(2025最新)Dubbo-admin实现分布式
  • 缓存与数据库一致性实战手册:从故障修复到架构演进