题目描述:

在股市的交易日中,假设最多可进行两次买卖(即买和卖的次数均小于等于2),规则是必须一笔成交后进行另一笔(即买-卖-买-卖的顺序进行)。给出一天中的股票变化序列,请写一个程序计算一天可以获得的最大收益。请采用实践复杂度低的方法实现。
给定价格序列prices及它的长度n,请返回最大收益。保证长度小于等于500。

测试用例:

[10,22,5,75,65,80],6

返回结果:

87

理解误区:

这道题有一个理解误区就是,如果是第i天卖出,那么是否可以在第i天接着买入,还是必须要在第i+1天的时候才能买入进行第二笔交易?我最初理解的是后者,但是后来自习想了想应该是前者

我的思路分析:

当时想着构造一个二维矩阵,profit[i][j]指的就是从第i+1天买入,到第j+1天(数组下标从0开始)卖出的收益,然后把所有的一次交易的收益全部求出来,这样,在这个二维数组里,对角线以上的部分会存有信息,但是对角线以及对角线以下的部分不会存有信息。然后求出一次交易的最大值。

之后开始求两次交易,两次交易的话,先遍历二维数组中已经求好的一次交易的收益,选择那些收益为正的,记录,比如说遍历到了profit[3][5]是一个正数,表示第4次买入,第6次卖出是有收益的(数组下表从0开始),那么接下来所需要做的,就是遍历从第7次到最后一次之间的交易记录的利润最大值,两者相加,然后和一次交易记录的最大值进行比较。

我的代码:

/*** 求最大收益,交易次数小于等于两次* @param prices 每一天的股票价格* @param n 天数* @return 返回小于等于两次交易所获取的最大利润*/public static int maxProfit(int[] prices, int n) {int[][] profit = new int[n][n];int max  = Integer.MIN_VALUE;//对角线无效,对角线以下的三角形无效//记录一次交易所获取的利润for(int i = 0;i<n;i++){for(int j = i + 1;j<n;j++){profit[i][j] = prices[j] - prices[i];//保存一次交易的最大值max = Math.max(profit[i][j], max);}}//遍历数组,计算两次交易的利润最大值for(int i = 0;i<n;i++){for(int j = i+1;j<n;j++){//只有当一次交易的利润是正的的时候,才会考虑计算第二次利润if(profit[i][j]>0){//在后续的日期里计算第二次交易的最大值for(int p = j+1;p<n;p++){//第i天卖出之后,第i天可以接着买入,所以这里用j+1而不是j+2for(int q = j+1;q<n;q++){//负利润被忽略if(profit[p][q]<0)continue;else{//计算两次交易的利润和int sum = profit[i][j] + profit[p][q];//与最大利润进行比较max = Math.max(sum, max);}}}}}}return max;}

出现的问题:

但是我的代码提交上去之后,发现,对于计算小的数组还是可以的,但是随着数组规模的扩大,时间就会花费很久,所以算法的性能不好,需要优化,其实也是,自己的代码存在至少两个缺点吧,第一,四层for循环嵌套,当n的规模变大的时候,就会比较耗时。二,没有利用动态规划的思想,通过做这道题,我领悟出了,动态规划的思想精髓其实是利用之前的决策结果,进行本次的决策,也就是说,动态规划的思想,是要求一定要使用之前的数据的,这样计算起来因为有之前的数据了,所以速度回很快。

改进思路:

自己看了一下网上的其他人的解法,发现果然很赞。别人的思路是这样的。用两个数组,一个数组preProfit[i],指的是第i+1天(数组下标从0开始)之前,当然也包括第i+1天的最大收益,需要保存的一个数据是第i+1天之前的最小价格,如果第i+1天的价格减去最小价格后的利润是要比不在这天卖出的利润大,那么就果断卖出,否则,这一天就不卖出,那么这天之前的最大利润和昨天的最大利润是一样的。这样就使用了昨天的数据,这才是正统的动态规划的思想。

另外一个数组postProfit[i]指定是第i天买入的话,之后所能获得的最大利润,需要保持一个变量记录第i+1天之后的最大价格,如果最大价格减去这一天的利润比明天之后卖出的最大利润要大的话,就卖出,否则,就等于明天之后卖出的最大利润。最后将两个数组求和,计算出总的最大利润

改进之后的代码:

/*** 求最大收益,交易次数小于等于两次* @param prices 每一天的股票价格* @param n 天数* @return 返回小于等于两次交易所获取的最大利润*/public static int maxProfit2(int[] prices, int n) {//第i天之前的最大利益int[] preProfit = new int[n];//第i天之后的最大int[] postProfit = new int[n];//总的最大利润int max = Integer.MIN_VALUE;//如果今天的价格减掉最小价格比截止到昨天的最大收益大,就用今天的价格减去最小价格,否则,用截止到昨天的最大收益int minBuy = prices[0];for(int i = 1;i<n;i++){minBuy = Math.min(minBuy, prices[i]);preProfit[i] = Math.max(preProfit[i-1], prices[i] - minBuy);}//如果最大价格减掉今天价格比明天以后买入的最大收益大,就用最大价格减掉今天价格,否则,用明天以后买入的最大收益int maxSell = prices[n-1];for(int i = n-2;i>=0;i--){maxSell = Math.max(maxSell, prices[i]);postProfit[i] = Math.max(postProfit[i+1], maxSell-prices[i]);}//求出两次交易的和,与总的最大利润进行比较for(int i = 0;i<n;i++){max = Math.max(preProfit[i] + postProfit[i], max);}return max;}

比较:

使用下面的算法的话,速度要快很多,当n是100的时候,我原来的那个算法是需要36毫秒,但是下边的算法只需要0毫秒

当n是500的时候,我原来的算法需要4428毫秒,接近4秒钟,显然对于这道题来说,就超时了,但是下边的算法只需要1毫秒!动态规划的威力可见一斑!!!

【动态规划】股票交易日相关推荐

  1. 股票交易日(动态规划)----美团2016研发工程师编程题(二)

    [编程题] 股票交易日 在股市的交易日中,假设最多可进行两次买卖(即买和卖的次数均小于等于2),规则是必须一笔成交后进行另一笔(即买-卖-买-卖的顺序进行).给出一天中的股票变化序列,请写一个程序计算 ...

  2. (动态规划)股票交易日问题

    携程2016开发工程师编程题第一题:股票交易日问题,只能一次买进卖出,本是一个很简单的问题,我却用了排序,用最大的减去最小的,好吧,居然通过了65%的测试用例,天真的以为自己终于做对一道线上编程题了, ...

  3. 股票交易日(动态规划)

    [编程题] 股票交易日 在股市的交易日中,假设最多可进行两次买卖(即买和卖的次数均小于等于2),规则是必须一笔成交后进行另一笔(即买-卖-买-卖的顺序进行).给出一天中的股票变化序列,请写一个程序计算 ...

  4. python 判断当前日期是否为股票交易日

    """ 需要先安装pip install chinesecalendar """ from chinese_calendar import ...

  5. 名企笔试:美团2016招聘笔试(股票交易日)

    美团2016招聘笔试(股票交易日) 题目描述 在股市的交易日中,假设最多可进行两次买卖(即买和卖的次数均小于等于2),规则是必须一笔成交后进行另一笔(即买-卖-买-卖的顺序进行).给出一天中的股票变化 ...

  6. 动态规划--股票(一次买入卖出和两次买入卖出)

    动态规划–股票(一次买入卖出和两次买入卖出)(c++) ##一次买入卖出 如果用一个数组代表股票每天的价格,可以选择从某一天买入,然后之后的一天卖出,求能够获得的最大收益. 例如,一只股票在某些时间节 ...

  7. 美团笔试题:股票交易日

    在股市的交易日中,假设最多可进行两次买卖(即买和卖的次数均小于等于2),规则是必须一笔成交后进行另一笔(即买-卖-买-卖的顺序进行).给出一天中的股票变化序列,请写一个程序计算一天可以获得的最大收益. ...

  8. 动态规划——股票问题

    动态规划专题--股票问题 虽然前两题用贪心可以做,但是本篇文章全部使用动态规划来解决问题,比较具有体系. 121. 买卖股票的最佳时机 动规五部曲:  第一步:确定dp数组(dp table)以及下标 ...

  9. LeetCode动态规划股票系列整理

    写在前面 股票感觉是LeetCode动态规划中系列最多的一类,交易次数不同,有冷冻期,含手续费,让买卖的最佳时机千奇百怪,但是只要掌握dp的方法,解决起来还是有套路可循的.依据dp的常规思想,股票问题 ...

最新文章

  1. mysql主从配置读写分离笔记
  2. UIProgressView(进度条控件)
  3. Oracle 执行计划
  4. PHP双引号的小隐患
  5. coreldraw的线条怎么变成圆头_别再穿到处撞的小白鞋了,这五款春夏小皮鞋,不管怎么搭配都好看...
  6. 将本地文件上传至Github【详细步骤】
  7. 转型产品经理该怎么做(适用于0-2岁的产品经理)
  8. linux终端美化,如何美化你的命令行终端Terminal
  9. Oracle数据库文件中的导入\导出(imp/exp命令)
  10. Python爬取最爱的电影并下载到本地(附源码)
  11. LPC1788入门手记
  12. 卅三先生的工程电磁场讲座.EEm05——边界条件001
  13. win7计算机设置成不黑屏,教你win7开机黑屏
  14. Notepad++插件: HexEditor
  15. OpenCV4学习笔记(31)——视频背景、前景提取分离及运动检测
  16. cesium 粒子特效
  17. 基于vue商品图片轮播和放大镜的方案
  18. 欢迎大家访问我的下载频道下载资源
  19. IDEA 启动报错:java.lang.IllegalStateException: failed to create a child event loop 问题解决
  20. java 线程状态_关于JAVA线程状态

热门文章

  1. momen.js记录下开发中用到的日期
  2. vscode突然无法登上remote端的一个解决方案
  3. python 使用smtp发送群邮件
  4. 一文带你全面了解MVC、MVP、MVVM模式(实例讲解)
  5. mac mysql中文乱码问题(亲测有效)
  6. HTML中的meta的属性作用
  7. Swagger2 总结
  8. 张蕾:北斗链将重新回到技术研发的道路上
  9. adb安装apk到手机
  10. 常见的网络准入控制技术对比表