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.

这道是买股票的最佳时间系列问题中最难最复杂的一道,前面两道 Best Time to Buy and Sell Stock 和 Best Time to Buy and Sell Stock II 的思路都非常的简洁明了,算法也很简单。而这道是要求最多交易两次,找到最大利润,还是需要用动态规划Dynamic Programming来解,而这里我们需要两个递推公式来分别更新两个变量local和global,参见网友Code Ganker的博客,我们其实可以求至少k次交易的最大利润,找到通解后可以设定 k = 2,即为本题的解答。我们定义local[i][j]为在到达第i天时最多可进行j次交易并且最后一次交易在最后一天卖出的最大利润,此为局部最优。然后我们定义global[i][j]为在到达第i天时最多可进行j次交易的最大利润,此为全局最优。它们的递推式为:

local[i][j] = max(global[i - 1][j - 1] + max(diff, 0), local[i - 1][j] + diff)

global[i][j] = max(local[i][j], global[i - 1][j])

其中局部最优值是比较前一天并少交易一次的全局最优加上大于0的差值,和前一天的局部最优加上差值中取较大值,而全局最优比较局部最优和前一天的全局最优,代码如下:

解法一:

class Solution {
public:
int maxProfit(vector<int> &prices) {
if (prices.empty()) return ;
int n = prices.size(), g[n][] = {}, l[n][] = {};
for (int i = ; i < prices.size(); ++i) {
int diff = prices[i] - prices[i - ];
for (int j = ; j <= ; ++j) {
l[i][j] = max(g[i - ][j - ] + max(diff, ), l[i - ][j] + diff);
g[i][j] = max(l[i][j], g[i - ][j]);
}
}
return g[n - ][];
}
};

下面这种解法用一维数组来代替二维数组,可以极大的节省了空间,由于覆盖的顺序关系,我们需要j从2到1,这样可以取到正确的g[j-1]值,而非已经被覆盖过的值,参见代码如下:

解法二:

class Solution {
public:
int maxProfit(vector<int> &prices) {
if (prices.empty()) return ;
int g[] = {};
int l[] = {};
for (int i = ; i < prices.size() - ; ++i) {
int diff = prices[i + ] - prices[i];
for (int j = ; j >= ; --j) {
l[j] = max(g[j - ] + max(diff, ), l[j] + diff);
g[j] = max(l[j], g[j]);
}
}
return g[];
}
};

我们如果假设prices数组为1, 3, 2, 9, 那么我们来看每次更新时local 和 global 的值:

第一天两次交易:      第一天一次交易:

local:    0 0 0       local:    0 0 0

global:  0 0 0       global:  0 0 0

第二天两次交易:      第二天一次交易:

local:    0 0 2       local:    0 2 2

global:  0 0 2       global:  0 2 2

第三天两次交易:      第三天一次交易:

local:    0 2 2       local:    0 1 2

global:  0 2 2       global:  0 2 2

第四天两次交易:      第四天一次交易:

local:    0 1 9       local:    0 8 9

global:  0 2 9       global:  0 8 9

在网友@loveahnee的提醒下,发现了其实上述的递推公式关于local[i][j]的可以稍稍化简一下,我们之前定义的local[i][j]为在到达第i天时最多可进行j次交易并且最后一次交易在最后一天卖出的最大利润,然后网友@fgvlty解释了一下第 i 天卖第 j 支股票的话,一定是下面的一种:

1. 今天刚买的
那么 Local(i, j) = Global(i-1, j-1)
相当于啥都没干

2. 昨天买的
那么 Local(i, j) = Global(i-1, j-1) + diff
等于Global(i-1, j-1) 中的交易,加上今天干的那一票

3. 更早之前买的
那么 Local(i, j) = Local(i-1, j) + diff
昨天别卖了,留到今天卖

但其实第一种情况是不需要考虑的,因为当天买当天卖不会增加利润,完全是重复操作,这种情况可以归纳在global[i-1][j-1]中,所以我们就不需要max(0, diff)了,那么由于两项都加上了diff,所以我们可以把diff抽到max的外面,所以更新后的递推公式为:

local[i][j] = max(global[i - 1][j - 1], local[i - 1][j]) + diff

global[i][j] = max(local[i][j], global[i - 1][j])

类似题目:

Best Time to Buy and Sell Stock with Cooldown

Best Time to Buy and Sell Stock IV

Best Time to Buy and Sell Stock II

Best Time to Buy and Sell Stock

参考资料:

https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Best Time to Buy and Sell Stock III 买股票的最佳时间之三的更多相关文章

  1. [LeetCode] Best Time to Buy and Sell Stock II 买股票的最佳时间之二

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

  2. [LeetCode] Best Time to Buy and Sell Stock 买卖股票的最佳时间

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

  3. [LintCode] Best Time to Buy and Sell Stock II 买股票的最佳时间之二

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

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

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

  5. 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 ...

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

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

  7. 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 ...

  8. [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 ...

  9. [LintCode] Best Time to Buy and Sell Stock 买卖股票的最佳时间

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

随机推荐

  1. 小萝贝控机大师工具推荐(一款在PC就能控制手机界面的工具)

    在一次写博客的过程中,要截取手机app上的几张图片,然后粘贴到博客里面去,不了解这个工具的时候,我就从手机上截图(使用其他的截图app或者使用手机自己的截图功能),然后再传送到电脑上,然后再放到博文中 ...

  2. ASP.NET Core 中文文档 第二章 指南(4.7)添加搜索

    原文:Adding Search 作者:Rick Anderson 翻译:魏美娟(初见) 校对:谢炀(Kiler) .孟帅洋(书缘).张仁建(第二年.夏) 在本节中,你可以为 Index 方法添加查询 ...

  3. [原创]django+ldap实现单点登录(装饰器和缓存)

    前言 参考本系列之前的文章,我们已经搭建了ldap并且可以通过django来操作ldap了,剩下的就是下游系统的接入了,现在的应用场景,我是分了2个层次,第一层次是统一认证,保证各个系统通过ldap来 ...

  4. [转]在 .NET 中远程请求 https 内容时,发生错误:根据验证过程,远程证书无效

    该文原网址:http://www.cnblogs.com/xwgli/p/5487930.html 在 .NET 中远程请求 https 内容时,发生错误:根据验证过程,远程证书无效.   当访问 h ...

  5. HTML基础标签

    [HTML写法标签][HTML字体段落标签][锚点][有序无序列表][表格] 一.HTML写法标签:双标签:<标签名>内容</标签名>单标签:<标签名 内容/> 二 ...

  6. Springmvc responsebody 返回对象属性 是date日期格式时 如何返回给前台自己想要的形式

    1添加依赖 <!-- Jackson Json处理工具包 -->            <dependency>              <groupId>org ...

  7. 浏览器对localstorage的支持情况以及localstorage在saas系统中的应用实践思考

    首先,还是要说,任何一种新特性的引入,通常有着其特有的场景和解决的目标需求,localstorage也一样.在我们的应用场景中,主要在金融业务服务的saas系统.其中涉及很多更改频率很多的元数据的客户 ...

  8. 交易系统使用storm,在消息高可靠情况下,如何避免消息重复

    概要:在使用storm分布式计算框架进行数据处理时,如何保证进入storm的消息的一定会被处理,且不会被重复处理.这个时候仅仅开启storm的ack机制并不能解决上述问题.那么该如何设计出一个好的方案 ...

  9. Atitit 游戏的原理与概论attilax总结

    Atitit 游戏的原理与概论attilax总结 1. 游戏历史2 1.1.1. 盘点PC游戏史上最重要的50款游戏2 1.1.2. 回味人类文明进程 五款经典的历史游戏2 2. 游戏类型(主要分为6 ...

  10. 《JS实现复制内容到剪贴板功能,可兼容所有PC浏览器,不兼容手机端》

    前记:本来原生的JS是有提供一个函数来实现这个功能(window.clipboardData),但是很遗憾,这个函数仅仅支持IE和FF浏览器,所以基本用处不大.下边介绍的是一个第三方插件库(ZeroC ...