編程之美 - 數組最大和的子序列

問題描述:

一個數組有N個元素,求這個數組中子數組的最大和。
要求:
  • 子數組是數組中連續的幾個元素
  • 數組的元素包含正數,負數,0

思路:
使用動態規劃的方式從第n-1個元素開始,向前累加。
如果當前值 大於當前值+以前和則在當前和的位置保存當前值,否則保存當前值+以前和
sum[n-2] = max(a[n-2],  sum[n-1]+a[n-1]),

程序示例 : getMaxSum()


擴展問題:
如果數組首尾相鄰,找到其中一段最大和。

思路:
問題大概存在三種情況

pic_1

第一種情況就是普通問題的解,
第二種和第三種是有循環的情形,從頭向尾循環和從尾向頭循環。

考慮先取得沒有循環時的一個最大值,再取得有循環時的最大值,再取他們中的最大值。
在計算循環的情況時,先找方向,確定是情況2,還是情況3。
再按照方向計算出一個循環情況下的最大值。

程序示例 : getMaxSumLoop()

#include <iostream>

using namespace std;

int max(int x, int y)
{
    return (x > y) ? x : y;
}

int getMaxSum(int arr[], int len)
{
    int i = 0, ret = 0, pos_s = 0, pos_e = 0;
    int* start = NULL;
    int* sum_max = NULL;

    if (len == 0)
        return 0;

    start = new int[len];
    sum_max = new int[len];

    start[len-1] = arr[len-1];
    sum_max[len-1] = arr[len-1];
    pos_s = pos_e = len-1;

    for (i = len-2; i>=0; i--)
    {
        start[i] = max(arr[i], arr[i] + start[i+1]);
        sum_max[i] = max(start[i], sum_max[i+1]);

        if (sum_max[i] == start[i])
        {
            if (start[i] == arr[i])
            {
                pos_s = i; pos_e = i;
            }
            else
            {
                pos_s = i;
            }
        }
    }
    ret = sum_max[0];
    delete[] start;
    delete[] sum_max;

    cout << "Max= " << ret << "    Start Pos = " << pos_s << "    End Pos = " << pos_e << endl;
    return ret;
}

int getMaxSumLoop(int arr[], int len)
{
    int i = 0, ret = 0, pos_0 = 0, pos_last = 0;
    int max_0 = 0, max_last = 0, sum_0 = 0, sum_last = 0;
    int M1 = 0, M2 = 0;

    if (len == 0)
        return 0;

    M1 = getMaxSum(arr, len);

    max_0 = arr[0];
    sum_0 = arr[0];
    max_last = arr[len-1];
    sum_last = arr[len-1];
    for (i = 1; i < len; i++)
    {
        sum_0 += arr[i];
        sum_last += arr[len-1-i];
        if (sum_0 >= max_0)
        {
            max_0 = sum_0;
            pos_0 = i;
        }

        if (sum_last >= max_last)
        {
            max_last = sum_last;
            pos_last = len-1-i;
        }
    }

    if (pos_0 >= pos_last)
    {
        if (max_0 > max_last)
        {
            M2 = max_0;
            sum_0 = max_0;
            for (i = len-1; i > pos_0; i--)
            {
                sum_0 += arr[i];
                if (sum_0 >= M2)
                {
                    M2 = sum_0;
                }
            }
        }
        else
        {
            M2 = max_last;
            sum_last = max_last;
            for (i = 0; i < pos_last; i++)
            {
                sum_last += arr[i];
                if (sum_last >= M2)
                {
                    M2 = sum_last;
                }
            }
        }
    }
    else
    {
        M2 = max_0 + max_last;
    }

    if (M1>M2)
        cout << "Max= " << M1 << endl;
    else
        cout << "Max (loop)= " << M2 << endl;

    ret = max(M1, M2);
    return ret;
}


void main()
{
    int test1[] = {1,-2,3,5,-3,2};
    int test2[] = {1,-2,3,5,-1,2};
    int test3[] = {-9,-2,-3,-5,-3};
    int len1 = sizeof(test1)/sizeof(test1[0]);
    int len2 = sizeof(test2)/sizeof(test2[0]);
    int len3 = sizeof(test3)/sizeof(test3[0]);

    getMaxSum(test1, len1);
    getMaxSum(test2, len2);
    getMaxSum(test3, len3);

    cout << "===============================" << endl;

    getMaxSumLoop(test1, len1);
    getMaxSumLoop(test2, len2);
    getMaxSumLoop(test3, len3);

    cin>> len1;
}




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