【LeetCode】Best Time to Buy and Sell Stock III (2 solutions)

來源:互聯網
上載者:User

標籤:des   style   blog   http   io   ar   color   os   使用   

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.

Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

 

解法一:基於Best Time to Buy and Sell Stock

代碼比較長,但是思路還是比較清晰,聽我解釋:

核心思想:

第一步:依照Best Time to Buy and Sell Stock求得最優買賣。值為maxGap,買賣點記作minInd和maxInd。

第二步:分兩種情況

case1: 在最優買賣的基礎上,另外加入一次有效買賣。

case2: 拆分最優買賣,即minInd在第一次買賣中,maxInd在第二次買賣中。

 

看著比較簡單,接下來我們糾結邊界情況:

case1中: 新加的一次有效買賣與最優買賣沒有交集。也就是說在minInd嚴格之前或者maxInd嚴格之後。

case2中: 第一次買賣的買點和賣點均有可能為minInd,第二次買賣的賣點和賣點均有可能為maxInd。

 

實現:

case1很容易,就是再跑兩次最優買賣,擇優加入。若不存在有效買賣則記為0。

minInd前的最優買賣記為partGap1,maxInd後的最優買賣記為partGap2。

case1Result = maxGap + max(partGap1, partGap2);

 

case2比較麻煩,我們來詳細解釋一下:

簡單分析可知:

兩次買賣的值分別為<minLeft, prices[j]>,<prices[k], maxRight>

其中minLeft為包括minInd在內的,minInd之前的最小值。minLeft為第一次買點的值,prices[j]為第一次賣點的值。

maxRight為包括maxInd在內的,maxInd之後的最大值。prices[k]為第二次買點的值,maxRight為第二次賣點的值。

因此必須滿足以下條件:

(1)minLeft所在位置<=minInd, j>=minInd

(2)k<=maxInd, maxRight所在位置>=maxInd

(3)j<=k 滿足Note的條件

case2Result = prices[j]-minLeft+maxRight-prices[k]

因為minLeft和maxRight都是確定的,最大化case2Result只需要求prices[j]-prices[k]的最大值。

這個問題化歸成了"最差買賣",即最優買賣問題的逆反問題,高點買入,低點賣出。

為了節省計算量,我在實現過程中,minLeft和maxRight都在case1的計算過程中附帶求出來了。

需要注意的是case1是不包含邊界的,因此minLeft和maxRight還應該與minInd、maxInd值權衡一下。

class Solution {public:    int maxProfit(vector<int> &prices)     {        if(prices.empty())            return 0;                    //at least 1 element        int maxV = prices[0];        int maxInd = 0;        int minV = prices[0];        int minInd = 0;        int curGap = 0;        int maxGap = 0;                for(vector<int>::size_type st = 1; st < prices.size(); st ++)        {            if(prices[st] > maxV)            {//maxV is free to update                maxV = prices[st];                curGap = maxV-minV;                if(curGap > maxGap)                {                    maxGap = curGap;                    maxInd = st;                    //minInd is the landmark position, changing all the time, thus cannot be determined                }            }            else if(prices[st] < minV)            {//if minV changes, all should restart                minV = prices[st];                maxV = prices[st];                curGap = 0;            }        }        //get the minInd        for(vector<int>::size_type st = 0; st < prices.size(); st ++)        {            if(prices[maxInd]-prices[st] == maxGap)            {                minInd = st;                break;            }        }        //arrive here, maxGap, maxInd, minInd is needed, thus avoid changing value                //case 1: the minInd~max is covered and add the 0~minInd(partGap1) or max~size-1(partGap2)        maxV = prices[0];        minV = prices[0];        curGap = 0;        int partGap1 = 0;        //minLeft can be prices[minInd]        int minLeft = prices[minInd];        for(vector<int>::size_type st = 1; st < minInd; st ++)        {            minLeft = min(minLeft, prices[st]);            if(prices[st] > maxV)            {//maxV is free to update                maxV = prices[st];                curGap = maxV-minV;                if(curGap > partGap1)                    partGap1 = curGap;            }            else if(prices[st] < minV)            {//if minV changes, all should restart                minV = prices[st];                maxV = prices[st];                curGap = 0;            }        }                maxV = prices[maxInd+1];        minV = prices[maxInd+1];        curGap = 0;        int partGap2 = 0;        //if maxInd are greater than prices.size()-3, then partGap2 remains 0.        int maxRight = prices[maxInd];    //maxRight initialized to prices[maxInd]        for(vector<int>::size_type st = maxInd+1; st < prices.size(); st ++)        {            maxRight = max(maxRight, prices[st]);            if(prices[st] > maxV)            {//maxV is free to update                   maxV = prices[st];                curGap = maxV-minV;                if(curGap > partGap2)                    partGap2 = curGap;            }            else if(prices[st] < minV)            {//if minV changes, all should restart                minV = prices[st];                maxV = prices[st];                curGap = 0;            }        }        //arrive here, partGap2, maxRight is needed        //caseResult may be either maxGap itself or adding one part        int case1Result = maxGap+max(partGap1, partGap2);                //case 2: i(index of minLeft<minInd)~minInd~j add k~maxInd~l(index of maxRight>k)        //case2Result = prices[j]-minLeft+maxRight-prices[k], that is max(prices[j]-prices[k]) && j<=k        maxV = prices[minInd];  //j        minV = prices[minInd];  //k        curGap = 0;        maxGap = 0; //now maxGap can be changed        int tmpInd = minInd;        for(vector<int>::size_type st = minInd; st <= maxInd; st ++)        {            if(prices[st] < minV)            {                minV = prices[st];                curGap = maxV-minV;                if(curGap > maxGap)                {                    maxGap = curGap;                    tmpInd = st;                    //maxInd is the landmark position, changing all the time, thus cannot be determined                 }            }            else if(prices[st] > maxV)            {                maxV = prices[st];                minV = prices[st];                curGap = 0;            }        }        int case2Result = maxGap-minLeft+maxRight;        return max(case1Result, case2Result);    }};

 

解法二:動態規劃

使用兩個數組,maxVec和minVec。

maxVec[i]表示從0到i的最優買賣值(低買高賣,為正)。需要一次從左往右遍曆。

minVec[i]表示從size-1到i的最差買賣值(高買低賣,為負)。需要一次從右往左遍曆。

一次遍曆數組,將對應元素相減:maxVec[i]-minVec[i]的最大值即解。

稍微分析一下發現,其實minVec是不需要的,在從右往左時候的當前值minGap即為minVec[i],

直接計算maxVec[i]-minGap,用來更新結果。這樣還能免去最後在數組上面的一次遍曆。

class Solution {public:    int maxProfit(vector<int> &prices)     {        if(prices.empty())            return 0;                    int size = prices.size();        int minLeft = prices[0];        int maxGap = 0;        //maxVec[i] means the maxGap from start to i (-->)        vector<int> maxVec(size, 0);                int maxRight = prices[size-1];        int minGap = 0;        //minVec[i] means the minGap from end to i (<--)        //vector<int> minVec(size, 0);                int result = 0;                for(int i = 0; i < size; i ++)        {            if(prices[i]-minLeft > maxGap)            //current is very big                maxGap = prices[i]-minLeft;            else if(prices[i] < minLeft)            //current is very small                minLeft = prices[i];            maxVec[i] = maxGap;        }        for(int i = size-1; i >= 0; i --)        {            if(prices[i]-maxRight < minGap)            //current is very small                minGap = prices[i]-maxRight;            else if(prices[i] > maxRight)            //current is very big                maxRight = prices[i];            //minVec[i] = minGap;                        if(maxVec[i]-minGap>result)                result = maxVec[i]-minGap;        }        return result;    }};

【LeetCode】Best Time to Buy and Sell Stock III (2 solutions)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.