题目如下:
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 (ie, you must sell the stock before you buy again).
分析如下:
之前的想法是错误的,然后参考了一下这里的思路,我觉得写得超级清晰的。直接复制粘贴来了:
“
和前两道题比起来的话,这道题最难了,因为限制了交易次数。
解决问题的途径我想出来的是:既然最多只能完成两笔交易,而且交易之间没有重叠,那么就divide and conquer。
设i从0到n-1,那么针对每一个i,看看在prices的子序列[0,...,i][i,...,n-1]上分别取得的最大利润(第一题)即可。
这样初步一算,时间复杂度是O(n2)。
改进:
改进的方法就是动态规划了,那就是第一步扫描,先计算出子序列[0,...,i]中的最大利润,用一个数组保存下来,那么时间是O(n)。
第二步是逆向扫描,计算子序列[i,...,n-1]上的最大利润,这一步同时就能结合上一步的结果计算最终的最大利润了,这一步也是O(n)。
所以最后算法的复杂度就是O(n)的。
”
我的代码
// 56ms过大集合
class Solution {
public:
int maxProfit(vector<int> &prices) {
if(prices.size()<=1)
return 0;
int max_profit=0;
int vec_size=(int)prices.size();
int* left_sz=new int[vec_size];
int* right_sz=new int[vec_size];
left_sz[0]=0;
right_sz[vec_size-1]=0;
int max_left_profit=0;
int max_right_profit=0;
int small_buy=0;
int large_sell=vec_size-1;
for(int j=1;j<vec_size;j++){
int i=j-1;
if(prices[i]<prices[small_buy])
small_buy=i;
int tmp_profit=prices[j]-prices[small_buy];
if(tmp_profit>max_left_profit)
max_left_profit=tmp_profit;
left_sz[j]=max_left_profit;
}
for(int j=vec_size-1;j>=1;j--){
int i=j-1;
if(prices[j]>prices[large_sell])
large_sell=j;
int tmp_profit=prices[large_sell]-prices[i];
if(tmp_profit>max_right_profit)
max_right_profit=tmp_profit;
right_sz[i]=max_right_profit;
}
for(int k=0;k<vec_size;k++){
if(left_sz[k]+right_sz[k]>max_profit)
max_profit=left_sz[k]+right_sz[k];
// std::cout<<"k="<<k<<" ,left_sz[k]="<<left_sz[k]<<" ,right_sz[k]="<<right_sz[k]<<std::endl;
}
delete [] left_sz;
delete [] right_sz;
return max_profit;
}
};
1. 其实我一开始想的是贪心策略。就是说,先找到一个时间段完成一次利润最大化的交易,然后在剩下的时间段中,完成一次利润最大化的交易。这是沿着Best Time to Buy and Sell Stock1的思路继续往下很容易出现的想法,但是等到提交后发现,这个想法是错误的。在 “ {6,1,3,2,4,7} ”这个测试案例上,就不能跑通过。如果用贪心算法,会找到[1,7]+[1,1],sum=6,但是,其实真正的最优解是[1,3]+[2,7],sum-7。也就是说,如果贪心的出来的第1次最大化交易中正好包含了可以拆分为两次的交易,并且,这两次交易正好只比贪心找出来的两次交易小一点,二者加起来的和就可能超过贪心策略找出来的和。
2. 这道题目的动态规划挺有意思的,第一眼觉得不是通常的那种bottom-up的形式,其实仔细想想,左边算一次,右边算一次,可以认为是两次运用了bottom-up的思想。
3. stock问题有4个系列,分别在 1, 2, 3, 4。
参考资料:
(1) UniEagle的博客