Best Time to Buy and Sell Stock

最近遇到一道題,數組表示當日股價,最多進行2次買賣,而且不能連續買,只能買賣買賣。問能賺到的最大值。

知道這是一道類型題,但是我想自己獨立解決。不過能力有限,最後還是參考了網絡中的大牛解法。這裏做一下總結。

參考推庫, 一個神奇的網站。
http://www.tuicool.com/articles/rMJZj2

能夠感到這是一道動態規劃的題,分成2部分,然後求和的最大值,但是如何對一部分求一次買賣所能獲得的最大值呢?

開始考慮記錄相鄰兩項的差,然後看看,當時沒有想到轉化爲,相鄰差數組的連續和的最大值,所以沒能找到答案。


先給出網上的做法。
找到最低點,一次計算每一點到最低點的差,然後求最大。
這裏需要注意,並不是求最高點和最低點的差。因爲最高點可能在最低點的前面。
仔細想一想,這也是一個動態規劃的問題,動態的找到相對最高點和最低點,然後比較找出最大。

這裏,用low 來記錄相對的最小值,每當有元素比low小,就更新相對最小值。
如果,比low 大,那麼計算差值和最大值比較。

int MaxProfitInStock(int *a, int length)
{
    bool isArrayVaild(int *, int);
    if(!isArrayVaild(a, length))
        return 0;

    int Max, low;
    //int cur = a[0];
    low = a[0];
    Max = 0;
    int i;
    for(i = 1; i < length; ++i)
    {
        if(a[i] < low)
            low = a[i];
        else if(a[i] - low > Max)
                Max = a[i] - low;
    }

    return Max;
}



現在我們知道了如何從數組中,一次買賣能獲得的最大值。
這裏需要對 MaxProfitInStock(int *a, int length) 做一點兒小小改動。
求 a[start~endL]中的買賣最大值。
那麼,我們就可以開始進行動態劃分,然後找到兩部分最大值和的最大值。

int MaxProfitInStock_DP(int *a, int start, int endL)
{
    if(NULL == a || start >= endL)
        return 0;

    int Max, low;
    //int cur = a[0];
    low = a[start];
    Max = 0;
    int i;
    for(i = start; i <= endL; ++i)
    {
        if(a[i] < low)
            low = a[i];
        else if(a[i] - low > Max)
                Max = a[i] - low;
    }

    return Max;
}

int MaxProfitInStock_maxBuy2_DP(int *a, int length)
{
    if(!isArrayVaild(a, length))
        return 0;

    int Max = 0;
    int i, tmp;
    for(i = 0; i < length; ++i)
    {
        tmp = MaxProfitInStock_DP(a, 0, i) + MaxProfitInStock_DP(a, i+1, length-1);
        if(tmp > Max)
            Max = tmp;
    }

    return Max;
}



顯然,求一部分的最大值複雜度 O(n),循環也是O(n),
所以整體是 O(n^2)。

思路2.

既然我們能在O(n)的時間求出 a[start ~ end]中差值的最大值,
那不妨記錄一下 a[0 ~ i] 和 a[i ~ length-1]的最大值,在求求和的最大值。

first[i] 表示 a[0 ~ i] 的最大值
last[i]  表示 b[i ~ length-1]的最大值

那麼整體的最大值 就是
max(first[i] + last[i])     0 <= i <= length-1
此時,整體的複雜度爲 O(n)

int MaxProfitInStock_maxBuy2_DP_1(int *a, int length)
{
    if(!isArrayVaild(a, length))
        return 0;

    int *first, *last;
    first = new int[length];
    last = new int[length];

    first[0] = 0;
    last[length - 1] = 0;

    int Max = 0;
    int cur, i;
    int low, high;
    low = a[0];
    for(i = 1; i < length; ++i)
    {
        if(a[i] < low)
            low = a[i];
        else if(a[i] - low > Max)
            Max = a[i] - low;

        first[i] = Max;
    }

    Max = 0;
    high = a[length - 1];
    for(i = length - 2; i >= 0; --i)
    {
        if(a[i] > high)
            high = a[i];
        else if(high - a[i] > Max)
            Max = high - a[i];

        last[i] = Max;
    }

    Max = first[0] + last[0];

    for(i = 1; i < length; ++i)
    {
        if(first[i] + last[i] > Max)
            Max = first[i] + last[i];
    }

    delete[] first;
    delete[] last;
    first = last = NULL;

    return Max;
}



補充,我自己開始的那個想法。

先記錄相鄰兩項差,然後求連續和的最大值。

int MaxProfitInStock_Mine(int *a, int length)
{
    if(!isArrayVaild(a, length) || (1 == length))
        return 0;

    int chaNum = length - 1;
    int *cha = new int[chaNum];
    int i;
    for(i = 0; i < chaNum; ++i)
    {
        cha[i] = a[i + 1] - a[i];
    }

    int Max = 0;
    int curSum = 0;
    //int start = -1;


    for(i = 0; i < chaNum; ++i)
    {
        curSum += cha[i];
        if(curSum > Max)
            Max = curSum;
        if(curSum < 0)
        {
            curSum = 0;
        }
    }
    delete[] cha;
    cha = NULL;

    return Max;
}














發佈了79 篇原創文章 · 獲贊 8 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章