问题:

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.

依旧还是那个熟悉的味道,如果III的另一个版本,那么III就是他们的一个升级版。

在这个版本中只能交易两次,也就是买卖各两次,其它条件依旧没有变(不熟悉的请参见I

分析:

 

在此题中,最多只能买卖两次,而且两次交易不能有交叉,也就是说应该是这样儿的(直线为时间,弧线为交易),

  或者 

不会出现:

问题三是问交易两次的最大收益,从上面的图我们可以看出由于两次交易没有交叉,我们可以考虑把这个问题拆分为两个问题:

1.第一次交易的最大收益(在前)

2.第二次交易的最大收益(在后)

那么现在问题又来了,在哪个位置拆分呢?几经思考发现从哪儿拆分都不合适,无论从哪儿拆分都不敢保证这种拆分办法就能得出最大收益,既然哪个位置拆分都不能保证最大收益,那如果我们每个位置都拆分一次,然后比较各自的最大收益,这样是否可行呢?在股票买卖时机问题1中我们用时间复杂度O(n)解决了一次交易的最大收益问题,那么在这里,每一次拆分会产生两个组,每个组用问题1的解法解答,那每一次拆分找出最大收益的时间复杂度为O(n),那拆分n-1次的时间复杂度就是O(n^2)了。按这种方法可以解决了,但是在LeetCode上提交貌似会报超时,而且,问题I和II都是在时间复杂度O(1)内解决的,没道理问题III要O(n^2),我们再仔细的考虑一下……

 

在问题I中我们采用动态规划的思想,通过分阶段找最优策略,后一阶段的最优策略由前一阶段的最优策略转化而来,换个角度,我们可以认为我们从第一阶段起,我们找到了每个阶段的最优解,在这道题中,也就是我们找到了从第1天到第i天的最大收益(i=2,3,4,…,n),只是在问题I中我们并没有把这些各个阶段的最大收益值保存下来。

 

那么我们回到问题III,我们先用I的办法把数组遍历一遍,并且声明一个数组profit[n],profit[i]保存第一天到第i+1天的最大收益,i=0,1,2,…,n-1,到此时间复杂度为O(n)。

此时相当于我们知道拆分后(假设从数组下标k处拆分)的第一组的最大收益,那么第二组呢?profit[i]只是记录了从0到i的最大收益,我们如何知道从k到i的最大收益呢?

 

再次分析问题I的解法,问题I的重点代码如下(完整的请参考http://www.cnblogs.com/chrischennx/p/4014422.html):

for(int i=1; i<prices.length;i++){
min = prices[i]<min?prices[i]:min;
profit = prices[i]-min>profit?prices[i]-min:profit;
}

它是通过找到各个阶段的最小值,然后用当前值减去最小值和前一阶段的最大收益比较得到最大收益,那么在问题III拆分后的第二组中我们是否也可以考虑用类似的办法来处理呢,每次拆分再计算k到i的最大收益肯定是不行的,因为每次时间复杂度为O(n),拆了n-1次时间复杂度就成了O(n^2),又回到刚开始的了,这不是我们需要的。

在问题I中是按数组从前往后考虑的,那么在第二组中,由于每次拆分都有最后一个值a[n-1],那么索性我们第二组从最后开始考虑。问题I是考虑前边儿找一个低的价格买入,后面找个高价卖出,也就是先找买入的价格,再找卖出的价格;那么从后开始考虑可以理解为:后面找个高价卖出,前面找个低价买入,也就是先找卖出的价格,再找买入的价格。也就是这样:

for(int i=a.length-2;i>=0;i--){
max = a[i]<max?max:a[i];
profit2[i] = max-a[i]>profit2[i+1]?max-a[i]:profit2[i+1];
}

然后我们就可以通过profit[i]+profit2[i]的最大值得到两次交易的最大收益。

 

到此问题就可以解决了,但是此时的空间复杂度为O(2n),其实还有更省的:不求profit2数组。

我们如此这般:

int max = a[a.length-1];
int result = profit[a.length-1];
for(int i=a.length-2;i>=0;i--){
max = a[i]>max?a[i]:max;
result = profit[i]+max-a[i]>result?profit[i]+max-a[i]:result;
}

其中profit[i]是按问题I的方法把求出的0到i的最大收益。

result = profit[i]+max-a[i]>result?profit[i]+max-a[i]:result;

这里用result直接用来保存最大收益,乍一看,容易理解为profit[i]+(max-a[i])和result比较,但是max-a[i]并不一定是第二组的最大收益,比如:[5,6,1,4],当i=1的时候,a[i]=6,max=6,但是此时的profit[1]+(max-a[1]),也就是profit[1]+0,肯定没有i=2,a[i]=1,max=4的时候大,profit[2]+3,看似这么理解是对的,但是,其实是错的,因为profit[i]+max-a[i]并不是在和它自己比,而是和result比,若之前的比较中有比较大的,那么就保存到result中了,之后的值比result小,result的值就不变了,所以最终result还是最大值。

如:[5,6,1,4]这个例子,

用问题I的方法计算出profit=[0,1,1,3],

当i=2的时候result=4,

当i=1的时候result = 1+4-4>4?1+4-4:4 = 4。

 

 


 

完整代码如下(java):

public class Solution {
public int maxProfit(int[] a) {
if(a==null || a.length==0)return 0;
int profit[] = new int[a.length];
int min = a[0];
profit[0] = 0;
for(int i=1;i<a.length;i++){
min = a[i]<min?a[i]:min;
profit[i] = a[i]-min>profit[i-1]?a[i]-min:profit[i-1];
} int max = a[a.length-1];
int result = profit[a.length-1];
for(int i=a.length-2;i>=0;i--){
max = a[i]>max?a[i]:max;
result = profit[i]+max-a[i]>result?profit[i]+max-a[i]:result;
} return result;
}
}

LeetCode——Best Time to Buy and Sell Stock III (股票买卖时机问题3)的更多相关文章

  1. LeetCode——Best Time to Buy and Sell Stock II (股票买卖时机问题2)

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

  2. LeetCode——Best Time to Buy and Sell Stock I (股票买卖时机问题1)

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

  3. LeetCode: Best Time to Buy and Sell Stock III 解题报告

    Best Time to Buy and Sell Stock IIIQuestion SolutionSay you have an array for which the ith element ...

  4. [LeetCode] Best Time to Buy and Sell Stock III 买股票的最佳时间之三

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

  5. [LeetCode] Best Time to Buy and Sell Stock III

    将Best Time to Buy and Sell Stock的如下思路用到此题目 思路1:第i天买入,能赚到的最大利润是多少呢?就是i + 1 ~ n天中最大的股价减去第i天的. 思路2:第i天买 ...

  6. LeetCode: Best Time to Buy and Sell Stock III [123]

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

  7. [Leetcode] Best time to buy and sell stock iii 买卖股票的最佳时机

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

  8. [leetcode]Best Time to Buy and Sell Stock III @ Python

    原题地址:https://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/ 题意: Say you have an array ...

  9. leetcode -- Best Time to Buy and Sell Stock III TODO

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

随机推荐

  1. String、StringBuilder 与 StringBuffer

    1. 在执行速度方面的比较:StringBuilder > StringBuffer 2. StringBuffer与StringBuilder,他们是字符串变量,是可改变的对象,每当我们用它们 ...

  2. 神经网络和Deep Learning

    参考资料: 在线免费书籍 http://neuralnetworksanddeeplearning.com/chap1.html Chapter 1 1.  perceptron 感知机 it's a ...

  3. bzoj 3055礼物运送 floyed + 状压DP

    bzoj 3055: 礼物运送 floyed first 设f[i][S]表示取到了S集合中的所有点(不一定是经过的所有点),最后停在了i的最优值. 初始就f[i][{i}] = dis[1][i] ...

  4. Outlook2016 新装进阶操作指南

    启动图片自动下载 键盘上同时按下WIN+R,弹出运行输入框,输入outlook,回车后打开Outlook 依次点击左上角文件,选项,信任中心,信任中心设置,自动下载 在窗口右边反勾选"在HT ...

  5. JavaScript把客户端时间转换为北京时间

    写在前面 写了一遍又一遍,网页老卡住,没保存下来,不写了. 时间转换代码 //获得北京时间 Date.prototype.getBJDate = function () { //获得当前运行环境时间 ...

  6. top命令

    TOP是一个动态显示过程,即可以通过用户按键来不断刷新当前状态.如果在前台执行该命令,它将独占前台,直到用户终止该程序为止.比较准确的说,top命令提供了实时的对系统处理器的状态监视.它将显示系统中C ...

  7. pair correlation ggpair ggmatrix

    https://zhuanlan.zhihu.com/p/23400450 首发于 R语言数据分析与可视化 关注专栏 登录 写文章     R 语言矩阵散点图 EasyCharts· 15 天前 散点 ...

  8. jedis池的作用

    一.jedis池的介绍 相信大家都用过线程池或者是jdbc的连接池,使用池可以减少系统在使用所需对象时创建对象的开销,从而提高系统性能和效率.jedis池也是如此,那么我们该如何使用jedis池呢? ...

  9. CSS知识回顾--读《CSS 那些事儿》笔记

    由于之前有了解过CSS的相关知识,有了一定的基础,所以读起<CSS 那些事儿>不是很有难度,况且我现在读起来时,CSS3和HTML5比较流行,这里只是记录一些CSS知识记录,不做详细铺开, ...

  10. JS 面向对象随笔

    1.一个对象的静态属性只能通过类名来访问 不能通过实例来访问 如下面定义个HelloWord的类 function HelloWord(){ console.log("这里是HelloWor ...