您的位置:首页 > 其它

最大子序列问题

2015-01-12 21:19 169 查看
问题描述

输入一组整数,求出这组数字子序列和中最大值。也就是只要求出最大子序列的和,不必求出最大的那个序列。例如:

序列:-2 11 -4 13 -5 -2,则最大子序列和为20。

复杂度为O(N^2)的算法

#include <stdio.h>
#include <stdlib.h>

int MaxSubSeqSum(const int *A, int N, int *start, int *end)
{
    int i = 0;
    int j = 0;
    int cur_sum = 0;
    int Max_sum = 0;

    for(i = 0; i < N; i ++)
    {
        cur_sum = 0;
        for(j = i; j < N; j ++)
        {
            cur_sum += A[j];
            if(cur_sum > Max_sum)
            {
                Max_sum = cur_sum;
                *start = i;
                *end   = j;
            }

        }
    }

    return Max_sum;
}

int main()
{
    int A[] = {-2,11,-4,13,-5,-2};
    int start_index, end_index;
    int max = MaxSubSeqSum(A,sizeof(A)/sizeof(A[0]),&start_index,&end_index);
    printf("MaxSubSeqSum is %d -- %d \n",A[start_index],A[end_index]);
    printf("max:%d \n",max);
}


算法度为O(NlogN)的算法

采用的是“分治“(divide-and-conquer)策略。思想是把问题分成两个大致相当的子问题,然后递归地对他们求解,这是”分“。”治“阶段将两个子问题的解合并到一起,可能再做一些附加的工作,最终得到整个问题的解。

上述问题,把序列分为两部分,最大子序列可能出现在左半部分,或者右半部分,或者是两者之间。两者之间的情况下,先对左半部分求以最后一个数字为结尾的最大序列和。然后对右半部分以第一个数字开始算最大序列和,将两者加起来即是。

int Max_3(int a, int b, int c)
{
    if(a < b)
        a = b;
    if(a < c)
        return c;
    else
        return a;
}
int MaxSubSeqSum2(const int *A, int left, int right)
{
    int MaxLeftSum, MaxRightSum, MaxSum;
    int MaxLeftBorderSum, MaxRightBorderSum;
    int LeftBorderSum, RightBorderSum;
    int center;
    int i;
    if( left == right)
    {
        if(A[left] > 0)
            return A[left];
        else
            return 0;
    }

    center = (left + right) / 2;

    MaxLeftSum = MaxSubSeqSum2(A,left,center);
    MaxRightSum = MaxSubSeqSum2(A,center + 1,right);

    MaxLeftBorderSum = 0;
    LeftBorderSum = 0;

    for(i = center; i >= left; i--)
    {
        LeftBorderSum += A[i];
        if(LeftBorderSum > MaxLeftBorderSum)
            MaxLeftBorderSum = LeftBorderSum;
    }

    MaxRightBorderSum = 0;
    RightBorderSum    = 0;
    for(i = center + 1; i <= right; i++)
    {
        RightBorderSum += A[i];
        if(RightBorderSum > MaxRightBorderSum)
            MaxRightBorderSum = RightBorderSum;
    }

    MaxSum = Max_3(MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum);

    return MaxSum;

}


算法复杂度为O(N)的算法

/* 如果a[i]为负数,那么它不可能代表最优序列的起点,因为任何包含a[i]的作为起点的子序列都可以通过
   用a[i+1]作为起点而得到改进。同理,任何小于零的子序列不可能是最优子序列的前缀。*/
int MaxSubSeqSum3(const int *A, int N, int *start, int *end)
{
    int i = 0;
    int j = 0;
    int cur_sum = 0;
    int Max_sum = 0;

    for(i = 0; i < N; i ++)
    {
        cur_sum += A[i];
        if(cur_sum > Max_sum)
        {
            Max_sum = cur_sum;
                *end   = i;
        }

        else if(cur_sum < 0)
        {
            cur_sum = 0;
            j = i + 1;
        }

        if(j <= *end)
            *start = j;

    }

    return Max_sum;
}

int main()
{
    int A[] = {-2,11,-4,13,-5,-2};
    int start_index, end_index;
    int max = MaxSubSeqSum3(A,sizeof(A)/sizeof(A[0]),&start_index,&end_index);
    printf("MaxSubSeqSum is %d -- %d \n",A[start_index],A[end_index]);
    printf("max:%d \n",max);
}


参考: http://www.cnblogs.com/CCBB/archive/2009/04/25/1443455.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: