动态规划DP(七) 股票交易

news2024/12/23 3:26:23

1.股票交易

在股票买卖的最佳时机问题中,给定一个数组,数组中的每个元素代表某一天的股票价格。你可以进行多次买入和卖出,但是必须在再次购买前卖出之前的股票。目标是找到最大的利润。

动态规划可以用于解决股票交易类的问题,其中最常见的问题是股票买卖的最佳时机问题(Best Time to Buy and Sell Stock)。

2.题目

1)

力扣icon-default.png?t=N658https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/找到当前位置之前的元素中的最小值,与当前位置的元素相减,遍历一维数组,找到最大差值。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int minp = prices[0];
        int n = prices.size();
        int res = 0;
        for(int i=1;i<n;i++){
            res = max(res, prices[i]-minp);
            minp = min(minp, prices[i]);
        }
        return res;
    }
};

2)

力扣icon-default.png?t=N658https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iii/这道题的难点在于最多购买股票两次,如果一直顺序考虑股票数组,就会变得很复杂,需要记录的值很多。

所有可以顺序加逆序考虑:

顺序:找到当前位置之前的最小值,当前位置元素与之计算差值,保留最大的差值。

逆序:找到当前位置之后的最大值,最大值与当前位置元素计算差值,保留最大的差值。

这样对于每个位置,都知道了这个位置之前一次购买卖出的最大利润,和这个位置以及这个位置之后一次购买卖出的最大利润。

把这个两个值相加,得到的就是每个位置最多购买两次彩票时的最大值。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();

        vector<int> dp(n,0);
        int minp = prices[0];
        for(int i=1;i<n;i++){
            dp[i] = max(dp[i-1], prices[i]-minp);
            minp = min(minp, prices[i]);
        }

        vector<int> dp2(n,0);
        int maxp = prices[n-1];
        for(int i=n-2;i>=0;i--){
            dp2[i] = max(dp2[i+1], maxp-prices[i]);
            maxp = max(maxp, prices[i]);
        }

        int res = 0;
        for(int i=0;i<n;i++){
            res = max(res, dp[i]+dp2[i]);
        }

        return res;
    }
};

3)

力扣icon-default.png?t=N658https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iv/题解:

这题需要额外考虑完成k次交易这一因素

所以转移方程为:buy[i][j]代表遍历prices[0...i]完成j笔交易,且此刻持有一只股票的最大收益。

sell[i][j]代表遍历prices[0...i]完成j笔交易,且此刻不持有股票的最大收益。

所以buy[i][j] = max(buy[i-1][j], sell[i-1][j]-prices[i])

取只考虑i-1只股票且完成j笔交易手上有股票的收益,或者只考虑i-1只股票且完成j笔交易购买当前这只股票收益

sell[i][j] = max(sell[i-1][j], buy[i-1][j-1]+prices[i])

取只考虑i-1只股票且完成j笔交易手上没有股票的收益,或者只考虑i-1只股票且此时卖出股票收益达到j笔交易的收益

这题好绕啊,建议自己码一下,会清晰很多。

代码:

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        int n = prices.size();
        vector<vector<int>> buy(n,vector<int>(k+1,INT_MIN/2));
        vector<vector<int>> sell(n,vector<int>(k+1,INT_MIN/2));
        if(2*k>=n) k = n/2;

        buy[0][0] = -prices[0];
        sell[0][0] = 0;
        
        for(int i=1;i<n;i++){
            sell[i][0] = 0;
            buy[i][0] = max(buy[i-1][0], sell[i-1][0]-prices[i]);
            for(int j=1;j<=k;j++){
                buy[i][j] = max(buy[i-1][j], sell[i-1][j]-prices[i]);
                sell[i][j] = max(sell[i-1][j], buy[i-1][j-1]+prices[i]);

            }
        }
        int res =  *(max_element(sell[n-1].begin(), sell[n-1].end()));
        return res>=0?res:0;
    }
};

因为是二维数组,且每次更新只用到[i-1]的值,所以肯定是可以压缩的。

压缩后,因为buy在sell前更新,所以 sell[i][j] = max(sell[i-1][j], buy[i-1][j-1]+prices[i])

就变成了 sell[i][j] = max(sell[i-1][j], buy[i][j-1]+prices[i])

又因为buy[i][j-1] = max(buy[i-1][j-1], sell[i-1][j-1]-prices[i]);

代入 sell[i][j],得到 sell[i][j] = max(sell[i-1][j], buy[i-1][j-1]+prices[i],sell[i-1][j-1] -prices[i]+prices[i])

比原本的 sell[i][j]多出了这一项:sell[i-1][j-1] -prices[i]+prices[i]

这一项表示在前i-1只股票中完成了j-1次交易,然后第j次交易是卖入第i只股票再在当天卖出。

所以也是sell[i-1][j]的一种特殊情况,所以多出的这一项不会比sell[i-1][j]大,也就不会影响最终的结果了。

所以是可以压缩数组的。

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        int n = prices.size();
        vector<int> buy(k+1,INT_MIN/2);
        vector<int> sell(k+1,INT_MIN/2);
        if(2*k>=n) k = n/2;

        buy[0] = -prices[0];
        sell[0] = 0;
        
        for(int i=1;i<n;i++){
            buy[0] = max(buy[0], sell[0]-prices[i]);
            for(int j=1;j<=k;j++){
                buy[j] = max(buy[j], sell[j]-prices[i]);
                sell[j] = max(sell[j], buy[j-1]+prices[i]);

            }
        }
        int res =  *(max_element(sell.begin(), sell.end()));
        return res>=0?res:0;
    }
};

速度明显变快了:

 4)

力扣icon-default.png?t=N658https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-cooldown/

股票交易的题,最后代码都不复杂,但是设计转移方程的过程真的很绕。

这题多了一个冷冻期,也就是除了买和卖之外,又多了一个冷冻的状态。

dp[i]表示第i天结束之后的最大收益:

  • dp[i][0]表示第i天结束之后,手上持有一只股票
  • dp[i][1]表示第i天结束之后,手上不持有股票,且处于冷冻期
  • dp[i][1]表示第i天结束之后,手上不持有股票,不处于冷冻期

接下来分类讨论:

dp[i][0]表示第i天结束之后,手上持有一只股票

所以手上这只股票可以是今天买的,也可以是前一天就买了的

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

dp[i][1]表示第i天结束之后,手上不持有股票,且处于冷冻期

这表示第i天卖了股票,所以第i天结束之后,才会处于冷冻期

dp[i]][0] = dp[i-1][0]+prices[i]

dp[i][1]表示第i天结束之后,手上不持有股票,不处于冷冻期

第i天结束之后不处于冷冻期,那么前一天结束之后可以是冷冻期,也可以不是冷冻期

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

代码:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        vector<vector<int>> dp(n, vector<int>(3,INT_MIN/2));
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        dp[0][2] = 0;

        for(int i=1;i<n;i++){
                dp[i][0] = max(dp[i-1][0], dp[i-1][2]-prices[i]);
                dp[i][1] = dp[i-1][0]+prices[i];
                dp[i][2] = max(dp[i-1][2], dp[i-1][1]);
           
        }
        return max(dp[n-1][1], dp[n-1][2]);
    }
};

转移方程中dp[i]只与dp[i-1]相关,所以可以压缩转移方程。简单地用六个变量来代替二维数组。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        vector<vector<int>> dp(n, vector<int>(3,INT_MIN/2));
        int f0,f1,f2,f3,f4,f5;
        f0 = -prices[0];
        f1 = 0;
        f2 = 0;

        for(int i=1;i<n;i++){
            
                f3 = max(f0, f2-prices[i]);
                f4 = f0+prices[i];
                f5 = max(f2, f1);
                f0 = f3;
                f1 = f4;
                f2 = f5;
           
        }
        return max(f1,f2);
    }
};

速度快了很多:

 

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

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

相关文章

ssl证书和域名过期提醒平台

由于经常忘记了证书是否要过期&#xff0c;导致过期了出现一些访问上的问题 docker安装部署 当然可以接入mysql&#xff0c;默认使用的sqlite version: "3" services:domain-admin:image: mouday/domain-admin:latestcontainer_name: domain-adminvolumes:- ./data:/…

菜鸡shader:L8 UV扰动动画——火焰和简单水面

文章目录 卡通火焰代码最后效果 水面代码最后效果 这此做笔记的两个shader其实是课程的作业&#xff0c;课程主要也是讲UV扰动的概念&#xff0c;因为课程的shader在另一台电脑上&#xff0c;做笔记就暂时不带他们了&#xff0c;简单做下火焰和水面的shader。 卡通火焰 火焰这…

FreeRTOS(队列)

队列 什么是队列&#xff1f; 队列又称消息队列&#xff0c;是一种常用于任务间通信的数据结构&#xff0c;队列可以在任务与任务间、中断和任 务间传递信息。 为什么不使用全局变量&#xff1f; 如果使用全局变量&#xff0c;兔子&#xff08;任务1&#xff09;修改了变量 a …

新版studio没法筛选Log

目录 方式一 简单粗暴&#xff0c;针对怀旧者&#xff0c;可切回原版log视图 方式二 学习新的log过滤方法 升级新版本AndroidStudio后&#xff0c;log日志变成以下样子&#xff0c;发现之前过滤error,infor的tab都不见了&#xff0c;瞬间不淡定了&#xff0c;查阅资料才发现…

DAY45:动态规划(五)背包问题:01背包理论基础+二维DP解决01背包问题

文章目录 背包问题大纲01背包01背包暴力解法01背包二维DP解法二维DP数组的解法DP数组含义递推公式初始化二维DP数组&#xff08;比较重要&#xff09;遍历顺序&#xff08;比较重要&#xff09; 二维DP数组完整版思路总结返回值为什么是二维数组最后一个元素DP推导过程与数组含…

selenium 根据期刊信息获取知网文献信息 pt.1

哈喽大家好&#xff0c;我是咸鱼 之前写过一篇获取知网文献信息的文章&#xff0c;看了下后台数据还挺不错 所以咸鱼决定再写一篇知网文献信息爬取的文章 需要注意的是文章只是针对某一特定期刊的爬取&#xff0c;希望小伙伴们把关注点放在如何分析网页以及如何定位元素上面…

python实现前后端学生管理系统(前后端不分离)

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;项目。 目录 1、前言2、简述实现内容首页注册登录管理员 3、详细代码3.1、项目目录3.2、templates3.2.1、testxz…

赛效:如何在线转换图片格式

1&#xff1a;点击左侧菜单栏里的“格式转换”&#xff0c;然后在转换格式菜单栏里点击上传按钮。 2&#xff1a;选择下方输出格式&#xff0c;点击右下角“开始转换”。 3&#xff1a;稍等片刻转换成功后&#xff0c;点击图片右下角的“下载”&#xff0c;将转换后的图片保存到…

UE5《Electric Dreams》项目PCG技术解析 之 PCGCustomNodes详解(四)ApplyHierarchy

继续解析《Electric Dreams》项目中的自定义节点和子图&#xff1a;ApplyHierarchy 文章目录 前导文章标准组合拳ApplyHierarchyExecute with ContextIteration Loop BodyPoint Loop Body应用场景 小结 前导文章 《UE5《Electric Dreams》项目PCG技术解析 之 理解Assembly&…

【Android】APT与JavaPoet学习与实战

PS&#xff1a;本文讲解的APT全称为Annotation Processing Tool&#xff0c;而非是Android Performance Tuner&#xff0c;这两种工具简称皆为APT&#xff0c;前者是“注释处理工具”&#xff0c;后者是“Android性能调试器”。 本文分别使用Java、kotlin 语言进行开发&#xf…

做一个游戏小项目有多简单?

认识一个朋友&#xff0c;学了很多年的 python, 还停留在 helloworld 阶段&#xff0c;每次拿起又放下&#xff0c;是不是很熟悉&#xff1f;每天都在想&#xff0c;我要学编程&#xff0c;我要学编程&#xff0c;但是又不知道从何学起&#xff0c;学了一点又不知道怎么用&…

java并发编程原理-----线程

目录 上下文切换 java代码创建线程的两种方式 线程的五个状态 线程join方法 多线程之间的影响 上下文切换 CPU的每一个核心同一时刻只能执行一个线程&#xff0c;但是我们会发现电脑同一时刻现实会进行几千个线程&#xff0c;这就是cpu在快速的切换执行线程&#xff0c;由…

Python中的迭代器

一、介绍 在Python中&#xff0c;迭代器是一种访问集合元素的方式&#xff0c;可以用于遍历数据集中的元素&#xff0c;而不需要事先知道集合的大小。迭代器可以被用于循环语句中&#xff0c;例如for循环&#xff0c;来遍历集合中的每个元素。 Python中的迭代器是一个实现了迭…

将Windows系统上的音频、视频通过iTunes传输到iPhone上

这个地方需要下载安装版的iTunes 下载地址&#xff1a; https://www.apple.com/itunes/download/win64 不要从Windows的APP Store中下载iTunes&#xff0c;不好使。 安装完成后&#xff0c;如果是导入一个文件夹中的资料&#xff0c;则点击 【文件】》【将文件夹添加到资料库】…

岛屿数量 (力扣) dfs + bfs (JAVA)

给你一个由 ‘1’&#xff08;陆地&#xff09;和 ‘0’&#xff08;水&#xff09;组成的的二维网格&#xff0c;请你计算网格中岛屿的数量。 岛屿总是被水包围&#xff0c;并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 此外&#xff0c;你可以假设该网格的…

在内卷化竞争时代,金龙鱼重返增长的关键到底是什么?

提到欧丽薇兰、胡姬花、香满园、海皇、金味、丰苑、锐龙洁劲100、丸庄酱油等品牌,多数消费者的第一反应是什么?多数消费者认为是某个不知名的新品牌。问题的重点不在产品&#xff0c;而在主品牌定位。 事实上&#xff0c;这都是金龙鱼母公司益海嘉里旗下的品牌。内行都知道益海…

“坏邻居”导致的kafka生产者TPS下降原因排查

背景&#xff1a; 今天测试了两种不同的场景下kafka producer的tps性能数据&#xff0c;两种场景下都是使用3个线程&#xff0c;每个线程都是对应一个kafka producer&#xff0c;测试发送到kafka集群的消息的量&#xff0c;两个场景的区别是场景A只发送kafka消息&#xff0c;场…

自定义类型

目录 什么是自定义类型 结构体 结构体的声明 常规结构体的声明形式 特殊的结构体声明形式 匿名结构体&#xff1a; 匿名结构体的重命名&#xff1a; 注意事项&#xff1a; 结构体的自引用 什么是结构体的自引用 结构体变量的定义与初始化 方法一&#xff1a; 方法…

总结python安装包(库)过程中的采坑

绝大数的包比如numpy、pandas可以用pip install或者conda install解决&#xff0c;使用pip时可以用pip -V命令看一下自己的pip安装在了哪个虚拟环境&#xff0c;一般pip安装在哪默认就把python包安装在哪。 pip -VC:\Users\20478>pip -V pip 23.1.2 from D:\Python\lib\sit…

Android Java代码与JNI交互 JNI子线程访问Java方法 (八)

🔥 Android Studio 版本 🔥 🔥 创建包含JNI的类 JNIInvokeMethod.java 🔥 package com.cmake.ndk1.jni;import com.cmake.ndk1.base.ICallbackMethod; import com.cmake.ndk1.base.IThreadCallback;public class JNIInvokeMethod {static {System.loadLibrary("…