LeetCode(123)Best Time to Buy and Sell Stock3

题目如下:

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个系列,分别在 1234


参考资料:

(1) UniEagle的博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值