線性查找-股票最佳收益

題目一:已知一個整型數組,表示某隻股票在每天的價格(假定每天價格保持一定,並且可買入可賣出),如果只允許買入一次賣出一次, 問最佳受益是多少?

這題跟數組最大距離恰成互補,這題簡化之後就是 已知A[n], 問找到 j > i, 使得A[j] - A[i] 最大。(數組最大距離是 找到 A[j] > A[i], 使得 j-i 最大)

要求A[j] - A[i] 最大,我們如果以j從0起始遍歷,無非就是讓A[j] 跟左邊元素中的最小值Lmin相比,顯然Lmin可以在j遍歷過程中不斷更新,所以這裏的線性查找就呼之欲出了。

int bestbuysellstock01(const int *A, int n, int& buy, int& sell){
    int min=0, maxDiff=0;
    buy = sell = 0;
    for(int i=1;i<n;++i){
        if(A[i] < A[min]){
            min = i;
        }else{
            int diff = A[i] - A[min];
            if(diff > maxDiff){
                maxDiff = diff;
                buy = min;
                sell = i;
            }
        }
    }
    return maxDiff;
}

很自然,用手指頭想想都能想到題目二:如果不限制交易次數,那麼最佳收益應該是多少?

唔,一次買入賣出是O(n),那麼多次交易貌似是O(n^2), 動態規劃??別急,我們來看看真實情況。

                                                         圖一,上證指數日k線圖

很清楚了吧?我們只要把每一段上漲都牢牢抓住,每段收益(比如圖一中圈出的區間)都收入囊中,那就是最大收益!所以,依然是線性,依然是一次遍歷

int keepbuysellstock(int *A, int n){
    int sum=0, buy=0, sell=0;
    for(int i=1;i<n;++i){
        if(A[i] >= A[i-1]){ //increasing
            if(buy == sell){
                buy = i-1;
            }
            sell = i;
        }else{ //falling down
            if(sell > buy){
                sum += A[sell] - A[buy];
                sell = buy = i-1;
            }
        }
    }
    if(sell > buy)
        sum += A[sell] - A[buy];
    return sum;
}

代碼實現中,關鍵在於極值點的處理:

1. “底部過後方知是底”,今日價格首次高於昨日價格時,昨日價格纔是局部底;

2. “頂部過後方知是頂”,今日價格首次低於昨日價格時,昨日價格纔是局部頂。

好吧,這道題對於投資過股票的人來說,實在是太親切了:)


注:題目一來自leetcode, 題目二在評論中也有出現,有個人說面試中面試官在出了題目一後緊接着出了題目二,然後他還沒做對。。。所以,不要被題目嚇死啊


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章