LeetCode123—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 algorithm to find the maximum profit. You may complete at most two transactions.
最多两次交易。
分析1
一种解法就是,把prices分为两半,0~i
、i+1~prices.size()-1
,在这种情况下,求出前i天的全局最优dp1[i],和后prices.size()-i
天的全局最优dp2[i],然后相加即可。这里的i要进行一次遍历,因此算法总体的复杂度是
O(n2)
。
分析2
参考:http://blog.csdn.net/linhuanmars/article/details/23236995
也是提供局部最优和全局最优的解法。
令:
local[i][j]
是在第i天卖出且经历j次交易的最大利益;
global[i][j]
是前i天经历j次交易的最大利益;
那么我们最终想要的结果就是
global[prices.size()−1][2]
动归方程如下:
diff=prices[i+1]−prices[i](1)
局部最优的动归方程:
local[i+1][j+1]=max(local[i][j+1]+diff,global[i][j]+max(diff,0))(2)
这里简单的解释一下式(2)
1.local[i][j+1]表示有j+1次交易,且最后一次卖出是在第i天;
2.global[i][j]表示有j次交易,且这j次交易是在前i天完成;
3.现在求local[i+1][j+1],也就是说最后一次卖出必须在第i+1天从1.来看,对应在第i天卖出,现在已经满足了j+1次交易了,那么如果要强行在i+1天卖出,则要把在第i天操作的这个卖出抵消掉(考虑diff=prices[i+1]-prices[i])。
从2.来看,global[i][j]相较于j+1次交易要少一次交易,由于这次卖出必须在第i+1天进行,由于前i天已经是全局最优,那么最后这一次买卖,只有两种情况:
a)第i天买入,第i+1天卖出
b)第i+1天买入,第i+1天卖出
上述两种情况就取决于第i+1天的价格是否比第i天的价格高了,没人愿意做亏本的买卖嘛,至少也是要保本。
全局最优方程可以这样写:
global[i+1][j+1]=max(global[i][j+1],local[i+1][j+1])(3)
这个相较于局部最优就好理解多了。
代码2
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
if (0 == len)
return 0;
vector<vector<int>>local(len + 1, vector<int>(3));//局部最优
vector<vector<int>>global(len + 1, vector<int>(3));//全局最优
for (int i = 0; i <len-1 ; i++)
{
int diff = prices[i + 1] - prices[i];
for (int j = 0; j < 2; j++)
{
local[i + 1][j + 1] = max(local[i][j + 1] + diff, global[i][j] + max(diff, 0));
global[i + 1][j+1] = max(global[i][j+1], local[i + 1][j+1]);
}
}
return global[len-1][2];
}
};
分析3
这里还有一个技巧就是降维,二维变一维,也就是说由于求解第i+1行j+1列的数据时,用到上一行第i行第j+1列,以及第i行第j列的数据。因为天数i是循环递增的,所以每次循环我们可以用一维数组保存当前行第i行的数据。又由于只能保存一行数据,我们在更新第i行第j列的数据时,需要用到上一行上一列[i][j]的数据,而这个数据又会被当前行上一列的数据覆盖[i][j-1],因此对于变量j来说,我们只能从后往前迭代。
代码3
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(0==prices.size())
return 0;
vector<int>local(3);//局部最优
vector<int>global(3);//全局最优
for (int i = 0; i < prices.size()-1; i++)
{
int diff = prices[i + 1] - prices[i];
for (int j = 1; j >= 0; j--)//从后往前
{
local[j + 1] = max(local[j+1]+diff,global[j]+max(diff,0));
global[j + 1] = max(global[j + 1], local[j + 1]);
}
}
return global[2];
}
};