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. IL实现简单的IOC容器

    既然了解了IL的接口和动态类之间的知识,何不使用进来项目实验一下呢?而第一反应就是想到了平时经常说的IOC容器,在园子里搜索了一下也有这类型的文章http://www.cnblogs.com/kkll ...

  2. WPF 自定义ContextMenu且为左键点击显示

    <Button Click="Button_Click_3" Style="{StaticResource NormalButtonStyle}"> ...

  3. SimpleSSO:使用Microsoft.Owin.Security.OAuth搭建OAuth2.0授权服务端

    目录 前言 OAuth2.0简介 授权模式 (SimpleSSO示例) 使用Microsoft.Owin.Security.SimpleSSO模拟OpenID认证 通过authorization co ...

  4. FlashBuilder项目环境配置

    一 .安装Flash Builder 1.  修改host文件 1.1 找到host文件,复制到桌面修改. 在"C:\Windows\System32\drivers\etc"文件 ...

  5. MySQL引擎、索引和优化(li)

    一.存储引擎 存储引擎,MySQL中的数据用各种不同的技术存储在文件(或者内存)中.这些技术中的每一种技术都使用不同的存储机制.索引技巧.锁定水平并且最终提供广泛的不同的功能和能力.通过选择不同的技术 ...

  6. ActiveMQ 简单搭建

    ========== ActiveMQ ============== JMS : topic : 一对多: 发布订阅: 不保证数据是否被接受: 不存储topic信息: Queue : 一对一: 点对点 ...

  7. PDO运用

  8. [连载]《C#通讯(串口和网络)框架的设计与实现》- 12.二次开发及应用

    目       录 第十二章     二次开发及应用... 2 12.1        项目配制... 3 12.2        引用相关组件... 4 12.3        构建主程序... 5 ...

  9. AlloyRenderingEngine之Shape

    写在前面 不读文章,只对代码感兴趣可以直接跳转到这里 https://github.com/AlloyTeam/AlloyGameEngine 然后star一下,多谢支持:). 游戏或者应用中,不是所 ...

  10. table 鼠标移上去改变单元格边框颜色。

    表格定义了border-collapse:collapse;边框会合并为一个单一的边框.会忽略 border-spacing 和 empty-cells 属性. 用td:hover,显示不全