【Best Time to Buy and Sell Stock III 】cpp

题目:

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

代码:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
            if (prices.empty()) return 0;
            const int len = prices.size();
            vector<int> l(len,0),r(len,0);
            // from left to right
            l[0] = 0;
            int l_min = prices[0];
            for ( int i = 1; i < l.size(); ++i )
            {
                l_min = std::min(l_min, prices[i]);
                l[i] = std::max(l[i-1], prices[i]-l_min);
            }
            // from right to left
            r[len-1] = 0;
            int r_max = prices[len-1];
            for ( int i = len-1; i >= 0; --i )
            {
                r_max = std::max(r_max, prices[i]);
                r[i] = std::max(r[i-1], r_max-prices[i]);
            }
            // travseral the best two times
            int max_profit = 0;
            for ( int i = 0; i < prices.size(); ++i )
            {    
                max_profit = std::max(max_profit, l[i]+r[i]);
            }
            return max_profit;
    }
};

tips:

此题说最多交易两次,求最大获利。

直觉的想法就是,把整个时间段分割成两部分( 共有prices.size()种分类方法 );分好后分别求两部分各自的最大值;这种算法是O(n²)时间复杂度的。

模仿之前求过的largest rectangle in histogram这道题的思路,能否利用dp思想,把算过的中间结果都存起来,把时间复杂度降低到O(n)。

想到这个思路就比较明确了:

1. 从左向右走一遍,l[i]存放0~i最多交易1次获利最大的值

2. 从右向左走一遍,r[i]存放i~prices.size()-1最多交易一次获利的最大值

3. 遍历数组l和数组r,通过遍历每种分割情况下的最大获利,并最终获得最终的最大获利值。

这里还有个细节可能会产生疑义:如果以第i天作为分割点,那么这第i天是算到前半截还是后半截呢

这里分两种情况:

1. 如果“前半截的最大利润”和“后半截的最大利润”只有一截涉及到了第i天,显然l[i]+r[i]这个算法是没问题的

2. 如果“前”、“后”两截都涉及到了第i天呢?这时候有两种理解方法:

  2.1 前后交易两次:前半截的某一天买入,第i天卖了,挣一笔;第i天卖完又买入了,到后面的某一天又卖了,挣第二笔。两笔加起来最大。

  2.2 前后交易一次:前半截的某一天买入,第i天虽然卖了获利最大,但是不卖,留着;等到后面的某一天发现获利最大,直接挣一笔最大的,同样获利最大。

因此,无论按照哪种理解方法,l[i]+r[i]都是合理的,不会因为第i天作为分割点而产生影响。

=====================================================

第二次过这道题,思路上有个地方没有理清(红字),在当天可以选择交易或者不交易,如果不交易那么等于左边(或右边)相邻元素的值。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
            if ( prices.empty() ) return 0;
            vector<int> l(prices.size(), 0);
            vector<int> r(prices.size(), 0);
            // l
            int minPrices = prices[0];
            for ( int i=1; i<prices.size(); ++i )
            {
                minPrices = min(prices[i], minPrices);
                l[i] = max(l[i-1], prices[i]-minPrices);
            }
            // r
            int maxPrices = prices[prices.size()-1];
            for ( int i=prices.size()-2; i>=0; --i )
            {
                maxPrices = max(maxPrices, prices[i]);
                r[i] = max(r[i+1], maxPrices - prices[i]);
            }
            // l to r
            int ret = 0;
            for ( int i=0; i<prices.size(); ++i )
            {
                ret = max(ret, l[i]+r[i]);
            }
            return ret;
    }
};

 

posted on 2015-06-02 14:18  承续缘  阅读(177)  评论(0编辑  收藏  举报

导航