1. 程式人生 > >陣列中兩個數相減(相加)的最大值

陣列中兩個數相減(相加)的最大值

題目:有一個數組,找出陣列中前面的數減去後面的數的最大值。例如陣列{9,1,7,18,3,-2,20,4,0,5},最大值是18-(-2)或者20-0。

解法一:把陣列分為左右兩個部分,相減最大的兩個數可能產生於左半部分,右半部分,或者橫跨左右兩個部分,最大值為這三種情況中數值最大的那個。對於兩個數位於左右兩部分的情況,最大的結果應該是左半部分的最大值減右半部分的最小值;左半部分和右半部分又可以各自劃分成兩部分,遞迴的求出最大值。時間複雜度O(nlogn).

int GetMaxCore(int *arr, int left, int right)
{
    if(left == right)
        return arr[left];

    int mid = (left+right)/2;
    int maxOfLeftSub = GetMaxCore(arr, left, mid);
    int maxOfRightSub = GetMaxCore(arr, mid+1, right);
    int maxOfLeft = INT_MIN;
    int minOfRight = INT_MAX;
    for(int i = left; i <= mid; ++i)
    {
        if(arr[i] > maxOfLeft)
            maxOfLeft = arr[i];
    }

    for(int i = mid+1; i <= right; ++i)
    {
        if(arr[i] < minOfRight)
            minOfRight = arr[i];
    }
    
    int tmp = maxOfLeftSub > maxOfRightSub ? maxOfLeftSub : maxOfRightSub;
    return tmp > (maxOfLeft-minOfRight) ? tmp : (maxOfLeft-minOfRight);
}

int GetMaxOfFormerSubLatter(int * arr, int n)
{
    return GetMaxCore(arr, 0, n-1);
}

解法二:使用兩個指標,初始值設為指向第一個數和第二個數,如下圖所示:


p1,p2指向前兩個數,初始的最大值就是max=9-1=8。然後p1保持不變,移動p2指標,每移動一次計算p1指向的值和p2指向的值之差,如果大於max,則更新max,直到p2指向第一個大於p1的值。


這時候再拿p1減去p2後面的值就沒有意義了,因為p1<p2,拿p1減p2後面的值肯定不會比p2減去它後面的值大。因此我們把指標p1指向p2的位置,p2後移一位。如下圖所示,直到p2到達陣列末尾。


這裡面跳過了第二幅圖中p1和p2中間的數相減的情況,當p1指向9,p2指向18,9和18之間的兩個數相減有沒有可能更大呢?可以證明不存在這種情況。假設p1和p2之間存在兩個數n1和n2有n1-n2更大,由於p2是第一個大於p1的數,所以n1<p1,,那麼p1-n2>n1-n2,矛盾,可知這種情況不存在。時間複雜度O(n).

程式碼如下:

int GetMaxOfFormerSubLatter(int * arr, int n)
{
    int p1 = 0;
    int p2 = 1;
    int max = arr[p1] - arr[p2];
    while(p2 < n)
    {
        while(arr[p2] < arr[p1] && p2 < n)
        {
            if(arr[p1] - arr[p2] > max)
                max = arr[p1] - arr[p2];
            ++p2;
        }
        p1 = p2;
        ++p2;
    }

    return max;
}

解法三:試想遍歷陣列時,如果當前數作為被減數,那麼前面的數和它相減要取得最大值應該拿前面最大的那個數和它減,掃描到當前值前面的最大值是可以記錄下來的。設前面某個數減去當前值的最大值為max,而陣列中當前值左邊的數的最大值為maxOfLeft。每掃描到一個數,計算maxOfLeft減去當前值,並與max比較,如果大則更新max。在指標移向下一個值之前更新左邊部分的數的最大值maxOfLeft。時間複雜度O(n).
int GetMaxOfFormerSubLatter(int * arr, int n)
{
    int max = arr[0] - arr[1];
    int maxOfLeft = arr[0];
    for(int i = 1; i < n; ++i)
    {
        int tmp = maxOfLeft - arr[i];
        if(tmp > max)
            max = tmp;
        if(arr[i] > maxOfLeft)
            maxOfLeft = arr[i];
    }

    return max;
}

擴充:對於兩個數相加的最大值,思路完全類似,可以將解法三中的“-”號改成“+”號就可以了。

相關推薦

no