• 【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;
        }
    };
  • 相关阅读:
    AIR 移动设备上的存储控制
    air写文件 SecurityError: fileWriteResource 时报错的解决方法
    [Embed(source="asset.swf")] 使用其中的所有资源
    as3调用外部swf里的类的方法
    Starling性能优化技巧十五则
    air开发中的requestedDisplayResolution 扫盲
    粒子编辑器的选择
    关于粒子..
    清理缓存功能的实现
    SegmentedControl的使用
  • 原文地址:https://www.cnblogs.com/xbf9xbf/p/4546359.html
Copyright © 2020-2023  润新知