前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >详解股票买卖算法的最优解(一)

详解股票买卖算法的最优解(一)

作者头像
HUC思梦
修改于 2020-09-11 14:10:15
修改于 2020-09-11 14:10:15
1.3K00
代码可运行
举报
运行总次数:0
代码可运行

前言

今天王子与大家分享的是LeeCode上有关如何买卖股票获取最高利润的题目。

主要用的技巧是“状态机”,那么什么是“状态机”呢?没听过的小伙伴会觉得它很高大尚,但今天我们讨论过后,你会发现其实它就是那么回事。

接下来,我们就以下边的题目为基础,讲解一下“状态机”是什么。

请看题:

看完题目后是不是觉得无从下手呢,没关系,接下来我们进入正题。

穷举框架

首先我们会想到,要解决这个问题需要怎么进行穷举,获取出最大的利润呢?要穷举的对象又是什么呢?

既然我们选择了状态机,那么要穷举的对象就是是状态,穷举状态的一种框架就是下边的模式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for 状态1 in 状态1的所有取值
    for 状态2 in 状态2的所有取值
        for ...
            dp[状态1][状态2][...] = 择优(选择1,选择2...

具体到我们的题目,分析可以知道我们每天都有三种选择:买入、卖出、卧倒不动,我们用buy、sell、rest表示这三种选择。

在此基础上,我们再次分析,可以知道每天是不能随意选择这三种选择的,它的选择是有限制条件的。

sell必须要在buy之后,buy又必须在sell之后(除了第一次)。而对于rest又有两种情况,如果是在buy之后rest,那么目前就是持仓状态,如果是在sell之后rest,那么目前就是空仓状态。而且我们还有一个买入次数K的限制,所以我们的buy是有限制的,buy<k, k>0。

分析题目,这个问题有三种状态,第一个是天数,第二是允许交易的最大次数k,第三个是当前的持有状态(空仓还是持仓,我们假设空仓为0,持仓为1)

看起来还可以理解吧,那么如何穷举呢?

我们用一个三维数组dp就可以存储这几种状态的全部组合,然后就可以用for循环完成穷举,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
dp[i][k][0 or 1]
0<=i<=n-1,1<=k<=K
//n为天数,K为最多交易次数,全部穷举如下

for 0<=i<n;
    for 1<=k<=K;
        for s in {0,1};
            dp[i][k][s] = max(buy,sell,rest)

如果上边的表达式还是没有看明白,那么我们可以用大白话描述出每一个状态的含义,比如说dp[3][2][1] 的含义就是:今天是第三天,我现在手上持有着股票,至今进行 2 次交易。再比如 dp[2][3][0] 的含义:今天是第二天,我现在手上没有持有股票,至今进行 3 次交易。这样就更容易理解了吧。

我们想要的最大利润值一定是 dp[n - 1][k][0],也就是最后一天,交易了k次,空仓状态。为什么说是空仓状态利润最大呢,可以这么理解,假设我们手上一共就这么多钱用于买卖股票,不考虑利润的情况下,如果买入股票变为持仓状态,可以看成是我们的总资金减去了买入的资金,实际上我们的资金是变少的,而卖出变为空仓状态,可以看成是我们把买入的资金又以不同的价格卖了出去,此时我们的总资金才真的增加了钱数,对于我们的总资金来说才算真正的盈利了。这其实就是我们平时理财的一个道理,如果买入了股票或基金,只要不卖出,你就不会真正的盈利,同样也不会真正的亏损,好了这是题外话,之后会有理财专辑专门谈谈理财,我们回归正题。

状态转移框架

我们知道了有多少状态,有多少选择,那么现在我们就开始考虑每种状态有哪种选择,他们之间如何组合。

三种选择buy、sell、rest是只与持有状态相关的,所以可以画出一个状态转移图如下:

通过这个图我们可以清楚的看到0和1之间是如何因为选择而转换的。可以写出状态转移方程如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
dp[i][k][0]=max(dp[i-1][k][0],dp[i-1][k][1]+prices[i])
                  max(    选择rest,       选择sell       )    
解释:今天没有持有股票有两种情况
        昨天没有持有,今天没有操作,所以今天没有持有
        昨天持有股票,今天卖出操作,所以今天没有持有

dp[i][k][1]=max(dp[i-1][k][1],dp[i-1][k-1][0]-prices[i])
                  max(    选择rest,       选择buyl       )    
解释:今天持有股票有两种情况
        昨天持有股票,今天没有操作,所以今天持有股票
        昨天没有持有,今天买入操作,所以今天持有股票

转移方程中的解释应该很清楚了,如果buy就从总钱数里减去prices[i],如果sell就给总钱数加上prices[i]。那么今天的最大利润就是在这两种选择中选取总钱数最大的那种情况。而且要保证交易次数的限制,buy了一次k就增加1,保证k<K。

现在我们已经把解题的核心部分,状态转移方程写完了,那么对于题目其实就是套用框架了,不过在套用之前,我们先把一些特殊情况考虑进去。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
dp[-1][k][0] = 0;
// 因为i>0,所以i=-1代表还没开始,利润为0

dp[-1][k][1] = 不存在;
// 还没开始是不可能持有股票的

dp[i][0][0] = 0;
// k=0代表还没交易过,利润当然是0

dp[i][0][1] = 不存在;
// k=0代表还没交易过,不可能持有股票

解决题目

第一题:k=1,即最多完成一次交易

直接套用框架如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
dp[i][1][0] = max(dp[i-1][1][0],dp[i-1][1][1]+prices[i]);
dp[i][1][1] = max(dp[i-1][1][1],dp[i-1][0][0]-prices[i])
                 =  max(dp[i-1][1][1],-prices[i]);
// 因为dp[i-1][0][0]=0

// 可以发现k都是1,也就是说k不影响状态转移,所以可以简化如下:
dp[i][0] = max(dp[i-1][0],dp[i-1][1]+prices[i]);
dp[i][1] = max(dp[i-1][1],-prices[i]);

同时我们还要考虑当i=0的时候,情况特殊,所以我们可以单独设置变量存储特殊情况

翻译成最终代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public int maxProfit(int[] prices) {
        int n=prices.length;
        int dp_i_0=0,dp_i_1=Integer.MIN_VALUE;
        for(int i=0;i<n;i++){
            dp_i_0=Math.max(dp_i_0,dp_i_1+prices[i]);
            dp_i_1=Math.max(dp_i_1,-prices[i]);
        }
        return dp_i_0;
    }

相信小伙伴们前边的内容理解清楚后,最终的代码是能够看懂的,我们继续看下一题。

第二题,k=+infinity,及不限制交易次数

如果k=+infinity,那么就可以认为k-1=k,所以可以引入改写框架如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
dp[i][k][0] = max(dp[i-1][k][0],dp[i-1][k][1]+prices[i]);
dp[i][k][1] = max(dp[i-1][k][1],dp[i-1][k-1][0]-prices[i])
                 =  max(dp[i-1][k][1],dp[i-1][k][0]-prices[i]);

// 可以发现k值全部相同,也就是说k不影响状态转移,所以可以简化如下:
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]);

直接翻译成代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public int maxProfit(int[] prices) {
        int n=prices.length;
        int dp_i_0=0,dp_i_1=Integer.MIN_VALUE;
        for(int i=0;i<n;i++){
            int temp=dp_i_0;
            dp_i_0=Math.max(dp_i_0,dp_i_1+prices[i]);
            dp_i_1=Math.max(dp_i_1,temp-prices[i]);
        }
        return dp_i_0;
    }    

第三题,k=+infinity ,而且带有冷冻期

解释一下题目,就是,卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。不限制交易次数

状态转移方程如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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]);
// 第i天选择buy的时候,要从i-2的状态转移(冷冻期1天)

直接翻译成代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public int maxProfit(int[] prices) {
        int n=prices.length;
        int dp_i_0=0,dp_i_1=Integer.MIN_VALUE;
        int dp_pre_0=0;//代表dp[i-2][0]
        for(int i=0;i<n;i++){
            int temp=dp_i_0;
            dp_i_0=Math.max(dp_i_0,dp_i_1+prices[i]);
            dp_i_1=Math.max(dp_i_1,dp_pre_0-prices[i]);
            dp_pre_0=temp;
        }
        return dp_i_0;
    }    

第四题,k=+infinity,带手续费

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

那么状态转移方程中,我们每次卖出的时候,把手续费减掉就可以了,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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]-fee);
// fee代表手续费,两个式子里随便一个减掉一次就可以了,可以看成是买入的时候交手续费或者卖出的时候交手续费

直接翻译成代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public int maxProfit(int[] prices,int fee) {
        int n=prices.length;
        int dp_i_0=0,dp_i_1=Integer.MIN_VALUE;
        for(int i=0;i<n;i++){
            int temp=dp_i_0;
            dp_i_0=Math.max(dp_i_0,dp_i_1+prices[i]);
            dp_i_1=Math.max(dp_i_1,temp-prices[i]-fee);
        }
        return dp_i_0;
    }    

总结

好了,看到这里以上4道关于股票买卖的算法题我们就完美解决了,小伙伴们看懂了吗,希望大家仔细思考解题思路,能实际运用这套框架哦,这是关于股票买卖算法的第一篇文章,后续会有补充内容,对剩下比较复杂的题目提供解题方法,欢迎阅读我的下一篇文章,一起研究算法吧。

往期文章推荐:

中间件专辑:

什么是消息中间件?主要作用是什么?

常见的消息中间件有哪些?你们是怎么进行技术选型的?

你懂RocketMQ 的架构原理吗?

聊一聊RocketMQ的注册中心NameServer

Broker的主从架构是怎么实现的?

算法专辑:

和同事谈谈Flood Fill 算法

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-09-08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Lurk黑客自称WannaCry为俄罗斯开发 德国执行反网络仇恨言论法
本文介绍了德国将开始执行反网络仇恨言论法,要求社交媒体网站迅速采取行动,消除仇恨言论,假新闻和非法材料。不删除明显非法的网站可能面临高达5000万欧元的罚款。这项法律要求网站被告知存在违法内容之后在24小时之内采取的行动。此外,Lurk黑客自称WannaCry实为俄罗斯开发,承认在FSB(俄罗斯联邦安全局信息安全中心)的要求下开发了WannaCry勒索软件和DNC黑客软件,并为其破解了美国民主党的服务器以及希拉里·克林顿的电子邮件服务器。
企鹅号小编
2018/01/08
6870
Lurk黑客自称WannaCry为俄罗斯开发 德国执行反网络仇恨言论法
QQ举报第三季度打击公示
腾讯举报中心作为QQ举报的官方受理渠道,致力于与用户共同打造一个健康、绿色的网络环境,日常除了提供QQ、微信和腾讯社交平台上各类违法违规行为的举报入口和举报受理外,还成立一系列违法犯罪举报专项,协助警方完成案件侦破和落地打击。
腾讯举报中心
2020/02/25
1K0
了解色情低俗有害信息
2、发送以色情为目的的情色文字、情色视频、情色图片、情色漫画等内容,但不限于上述形式;
腾讯举报中心
2020/02/25
2.4K0
【极客周刊】“无现金“受阻,暗网电商被黑,社交平台遭立案调查...
“无现金”为时尚早 近期,随着8月初全球首个“无现金日”的过去,社会中针对“无现金社会”的争论越来越激烈,贬褒不一,而且官方给出的观点更是成为了焦点。 据媒体报道,近日某银行机构下发通知:最近一些地区
一川水巷
2018/05/18
9350
网络安全宣传周 - 利用钓鱼 WiFi 窃取微信朋友圈私人信息
随着智能手机的普及和社交媒体的广泛应用,人们在享受便捷的网络服务时,个人隐私信息也面临着越来越多的威胁。黑客利用钓鱼 WiFi 窃取用户微信朋友圈等私人信息的行为,给用户带来了极大的安全隐患。
Khan安全团队
2024/08/18
3330
网络安全宣传周 - 下载文件替换
在数字化时代,人们越来越依赖网络进行各种活动,包括文件下载。然而,公共 Wi-Fi 网络的安全性常常被忽视,为不法分子提供了可乘之机。下载替换欺骗作为一种新兴的网络攻击手段,给用户的设备和数据安全带来了严重威胁。
Khan安全团队
2024/08/18
1200
腾讯2018守护者计划大会 | 黑产对抗进行中
非法入侵计算机系统、窃取企业和个人用户信息、制作销售黑产工具以及从事电信网络诈骗……近年来黑色产业威胁愈演愈烈,各环节分工合作多元化、专业化、集团化致使网络黑产形式严峻,一些常见的形态如木马,流量劫持,DDoS攻击——普通用户都可以说是耳熟能详了。 而从腾讯方面公布的数据来看,中国网络黑产威胁源主要表现形式有:非法获取公民个人信息、木马病毒威胁、恶意网站威 胁、黑客渗透威胁、流量劫持威胁、DDoS 攻击威胁、为黑客攻击 供技术支持。而这些黑色产业的威胁源还在随着时间的变化不断呈现出全新的面貌。** 1月14
FB客服
2018/02/24
2.1K0
腾讯2018守护者计划大会 | 黑产对抗进行中
中央网信办印发《关于切实加强网络暴力治理的通知》
网络暴力针对个人集中发布侮辱谩骂、造谣诽谤、侵犯隐私等违法信息及其他不友善信息,侵害他人合法权益,扰乱正常网络秩序。为切实加大网暴治理力度,进一步压实网站平台主体责任,健全完善长效工作机制,有效保障广大网民合法权益,维护文明健康的网络环境,中央网信办印发《关于切实加强网络暴力治理的通知》,内容如下。
FB客服
2022/11/14
6300
中央网信办印发《关于切实加强网络暴力治理的通知》
深度调查“比特币敲诈者”背后藏大型僵尸网络
腾讯云开发者社区
2017/05/15
2.7K1
深度调查“比特币敲诈者”背后藏大型僵尸网络
网络安全宣传周 - 电信诈骗
电信诈骗在网络安全领域已成为一颗毒瘤,严重威胁着人们的财产安全和社会的稳定。据统计,近年来电信网络诈骗犯罪持续呈现高发态势,犯罪形式多达 48 类。电信诈骗不仅会让个人遭受巨大的经济损失,还会扰乱正常的生产生活秩序。例如,刘女士在交友 APP 上被诈骗 50 余万元,王女士也因交友诈骗损失数万元。这些案例充分说明电信诈骗危害巨大,网络安全形势极为严峻。
Khan安全团队
2024/11/02
1530
遭遇网络勒索:法律义务梳理与合规建议
在2021年的《政府工作报告》中,李克强总理提出要加快数字化发展,打造数字经济新优势,协同推进数字产业化和产业数字化转型。在数字化发展的过程中,伴随着效率的提升,网络安全风险的敞口也不断增大。而在各种网络安全风险中,勒索软件已经成为最为严重的威胁之一,甚至会直接危害人身安全。2020年9月德国杜塞尔多夫大学医院遭受勒索软件攻击,一名患者被转移至附近的其他医院后不幸身亡。勒索所造成的危害已经无法忽视。
FB客服
2021/04/16
7580
遭遇网络勒索:法律义务梳理与合规建议
早报:金融App出故障 男子获利1125万被判盗窃罪获刑11年
1、金融App出故障 男子获利1125万被判盗窃罪获刑11年 律师吴绍平回忆,会面时,叶榅飞始终在问:欠钱还了就好了,真的要被判刑? 叶榅飞是福建人,在上海生活多年。去年6月,在使用一款名为“壹钱包”的金融理财软件时,叶榅飞发现,存入的钱被退回银行卡内,但软件上的账户余额却相应增加。此后8天,叶榅飞利用这一故障,前后转账超过350次,套现1125万元。 “壹钱包”平台运营方报警后,叶榅飞被警方拘留。近日,叶榅飞的辩护律师吴绍平收到该案一审判决,法院以盗窃罪判处叶榅飞有期徒刑11年,并处罚金50万元。叶榅飞
用户1335017
2018/03/09
9270
早报:金融App出故障 男子获利1125万被判盗窃罪获刑11年
网络安全宣传周 - 二维码植入木马
随着移动互联网的普及和二维码技术的广泛应用,二维码成为了信息传播和获取的重要途径。然而,这一便捷的技术也被不法分子利用,通过在二维码中嵌入恶意链接,诱导用户扫描,从而实现木马程序的植入,给用户的手机安全和个人隐私带来了严重威胁。
Khan安全团队
2024/08/18
2680
探探涉黄遭下架,但社交黑产会消失吗?
经小伙伴们证实,探探 APP 的身影在各大安卓应用商店均已消失,只有官方网站和苹果 App Store 有下载通道。
数据猿
2019/05/14
1.5K0
探探涉黄遭下架,但社交黑产会消失吗?
揭秘各国网军,未来网战哪家强?
网络战是一种破坏性极强的“顶级”作战形式,它的实施关系到国家的安危与存亡。网络武器的巨大威力与核打击类似,可以使整个网络陷入瘫痪,对整个社会的中枢神经系统造成极大打击,由此导致实体空间的一些连锁反应。对网络依赖越深的国家,受到的伤害就越重。 近年来,全球国家都对无形的“网战”产生浓厚兴趣。网络部队哪家强?在陆海空之外的网络虚拟空间成为新的现实战场之时,除了美国,全球多个国家都在进行网络部队的军备竞赛,各国“网络部队”的步伐与时俱进。值此八一建军节之际,小编今天带大家看看各国网军的真容。 美国:设“网络司令
安恒信息
2018/04/11
2.5K0
揭秘各国网军,未来网战哪家强?
《网络安全法》执法案例汇总
自《网络安全法》生效以来,与其相关的执法行为逐渐走向常态。本文收集了2017年6月1日至8月18日间各地落实《网络安全法》相关规定的执法案例,包括: 腾讯微信、新浪微博、百度贴吧涉嫌违反《网络安全法》被立案调查;BOSS直聘被网信办责令整改;汕头某公司未及时履行网络安全义务,网警依据网安法责令改正;重庆一网络公司未留存用户登录日志被网安查处;四川一网站因高危漏洞遭入侵被罚;宿迁网警成功查处全省首例违反《网络安全法》接入违规网站案;山西忻州市某省直事业单位网站不履行网络安全保护义务被处罚;淘宝网、同花顺金
FB客服
2018/03/01
2.9K0
《网络安全法》执法案例汇总
中东泥潭里的伊朗,网络战能力是否被严重低估?
最近的网络空间,并不安宁。美国总统特朗普在接受媒体采访时证实,他于2018年批准了对俄罗斯互联网研究院的网络攻击,发动攻击的正是由特朗普在2017年下令组建的美军网络司令部。
FB客服
2020/07/28
6690
新国家安全法通过,首次明确“网络空间主权”概念
摘自:新华社 新的国家安全法高票通过,习近平签署第29号主席令予以公布。新国家安全法对港澳特区维护国家安全的责任,提出了原则要求,对11个领域的国家安全任务进行了明确,自公布之日起施行。 7月1日,十二届全国人大常委会第十五次会议高票表决通过了新的国家安全法。国家主席习近平签署第29号主席令予以公布。法律对政治安全、国土安全、军事安全、文化安全、科技安全等11个领域的国家安全任务进行了明确,自公布之日起施行。 新国家安全法对港澳特区维护国家安全的责任提出原则要求。 新国家安全法概
大数据文摘
2018/05/21
1.5K0
网络安全宣传周 - 网络诈骗
当前,网络诈骗呈现出高发态势,已成为严重威胁社会稳定的一大难题。从个人层面来看,网络诈骗给受害者带来了巨大的经济损失和心理创伤。许多人辛苦积攒的钱财被骗子瞬间骗走,甚至可能导致家庭破裂。例如,一些老年人因轻信网络诈骗分子的虚假宣传,将养老钱投入到所谓的 “高回报” 投资项目中,结果血本无归。对于企业而言,网络诈骗也带来了诸多风险。企业可能因员工遭受网络诈骗而导致重要商业信息泄露,影响企业的正常运营和竞争力。据统计,每年因网络诈骗导致的企业经济损失高达数十亿。在社会经济层面,网络诈骗严重扰乱了市场经济秩序。骗子通过各种手段骗取钱财,使得资金无法正常流动,影响了经济的健康发展。
Khan安全团队
2024/11/02
1550
网信办修改《网络安全法》的决定(征求意见稿)公布
2022年9月14日,国家互联网信息办公室发布关于公开征求《关于修改〈中华人民共和国网络安全法〉的决定(征求意见稿)》意见的通知。 为了做好《中华人民共和国网络安全法》与相关法律的衔接协调,完善法律责任制度,保护个人、组织在网络空间的合法权益,维护国家安全和公共利益,我办会同相关部门起草了《关于修改〈中华人民共和国网络安全法〉的决定(征求意见稿)》,现向社会公开征求意见。公众可通过以下途径和方式反馈意见: 1、通过电子邮件将意见发送至:law@cac.gov.cn。 2、通过信函将意见寄至:北京市西城区车公
云头条
2022/09/15
1.1K0
推荐阅读
相关推荐
Lurk黑客自称WannaCry为俄罗斯开发 德国执行反网络仇恨言论法
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档