Best Time to Buy and Sell Stock III

题目等级:Hard

题目描述:

Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete at most two transactions.

Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).

Example 1:

Input: [3,3,5,0,0,3,1,4]
Output: 6
Explanation: Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3.

Example 2:

Input: [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are
engaging multiple transactions at the same time. You must sell before buying again.

Example 3:

Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.

  题意:给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。设计一个算法来计算所能获取的最大利润。最多允许完成两次交易,必须在再次购买前出售掉之前的股票。


解题思路(动态规划+二分法):

  前面两道题分别是允许一次交易和允许无数次交易,这里的改变是允许两次交易,相对难度就比较大。

  首先回顾一下允许一次交易的情形,买卖股票的问题我们可以看到是一个明显的分阶段决策的问题,每一阶段的决策会影响到整体的决策,从而影响最优化结果。所以在一次交易问题中,我们使用动态规划,采用以下递推公式进行解决:dp[i]=max(price[i]-min,maxProfit)

  这里是两次交易,解法是:将两次交易转化成两个一次交易,第i天之前一次,第i天之后一次。

  我们可以看到,两次交易一定是先完成了一次,接下来再完成第二次,所以可以使用二分的思想,以第i天为分界,第i天之前完成一次交易,第i天之后完成一次交易,分别得到每一次交易的最大值,最后遍历一次找到最合适的i,则对应的两次收益之和就是我们求的结果。

  我们用dp1[i]表示从第一天到第i天完成一次交易的最大收益,用dp2[i]表示从第i天到最后一天完成一次交易的最大收益。则只需要分别计算出这两个数组dp1和dp2即可。

  对于dp1,很简单,从前往后遍历,这就是我们在一次遍历时的递推公式:dp1[i]=max(dp[i-1],prices[i]-min)

  对于dp2,稍作变形,从后往前遍历,维护一个最大值,递推公式:dp2[i]=max(dp[i+1,max-prices[i]])

  最后,我们要求的结果就是:res=max(dp1[i]+dp2[i]),也就是找到最合适的i值。

class Solution {
public int maxProfit(int[] prices) {
/*分成两次,第i天之前一次,第i天之后一次,转化成两个一次交易的问题
从前往后:dp1[i]=max(dp[i-1],prices[i]-min),从第一天到第i天完成一次交易的最大收益
从后往前:dp2[i]=max(dp[i+1,max-prices[i]]),从第i天到最后一天完成一次交易的最大收益
*/
if(prices==null || prices.length==0)
return 0;
int len=prices.length;
int[] dp1=new int[len];
int[] dp2=new int[len];
//从前往后
int min=prices[0];
dp1[0]=0;
for(int i=1;i<len;i++){
dp1[i]=Math.max(dp1[i-1],prices[i]-min);
min=Math.min(prices[i],min);
}
//从后往前
int max=prices[len-1];
dp2[len-1]=0;
for(int i=len-2;i>=0;i--){
dp2[i]=Math.max(max-prices[i],dp2[i+1]);
max=Math.max(prices[i],max);
}
//合并得到结果
int res=0;
for(int i=0;i<len;i++){
if(dp1[i]+dp2[i]>res)
res=dp1[i]+dp2[i];
}
return res;
}
}

  时间复杂度:O(3n),空间复杂度:O(2n)

总结

  本题难度比较大,实际上这就是一次交易的变形考法,主要是要熟悉动态规划的解法,正确写出递推公式。

最新文章

  1. git代码冲突解决
  2. 用命令测试安装好的OpenStack环境
  3. Javascript样例之文档章节滚动全版(DOM)
  4. eval(gzinflate(base64_decode N层,自动解密
  5. openstack 排错
  6. 数据聚合 &amp; 分组:新一代系统监控的核心功能
  7. Spring之单元测试
  8. 极路由器刷机安装ss插件最新教程
  9. 笔记整理--C语言
  10. [ZOJ3256] Tour in the Castle
  11. jQuery中animate()方法用法实例
  12. Save results to different files when executing multi SQL statements in DB Query Analyzer 7.01
  13. Bootstrap在线引用css和js
  14. 【大数据安全】基于Kerberos的大数据安全验证方案
  15. 专注于C#.Net WPF软件开发-软件反编译-软件破解-逆向-靖芯科技-包括安卓APK反编译
  16. 【Docker】-NO.132.Docker.1 -【Docker 修改容器端口】
  17. BinDiff安装使用教程
  18. 【转】Mybatis源码解读-设计模式总结
  19. linux find 只获取文件名而去除路径
  20. js常见知识点3.面向对象之继承、设计模式

热门文章

  1. noi.ac NA536 【打地鼠】
  2. Jenkins环境搭建遇到的问题
  3. Tushare基础调用及处理
  4. cdh搭建仓库
  5. Confluence 6 图片文件
  6. HGOI20190812 省常中互测5
  7. npm全局路径及cache路径设置
  8. rem等比例自适应手机尺寸
  9. ZooKeePer总汇
  10. 完美解决前端跨域之 easyXDM 的使用和解析