01-复杂度1 最大子列和问题

给定KK个整数组成的序列{ N_1N1​​, N_2N2​​, ..., N_KNK​​ },“连续子列”被定义为{ N_iNi​​, N_{i+1}Ni+1​​, ..., N_jNj​​ },其中 1 \le i \le j \le K1ijK。“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。

本题旨在测试各种不同的算法在各种数据情况下的表现。各组测试数据特点如下:

  • 数据1:与样例等价,测试基本正确性;
  • 数据2:102个随机整数;
  • 数据3:103个随机整数;
  • 数据4:104个随机整数;
  • 数据5:105个随机整数;

输入格式:

输入第1行给出正整数KK (\le 100000100000);第2行给出KK个整数,其间以空格分隔。

输出格式:

在一行中输出最大子列和。如果序列中所有整数皆为负数,则输出0。

输入样例:

6
-2 11 -4 13 -5 -2

输出样例:

20




---------------------------------------------
这里给出四个算法

算法1:空间复杂度 0(n^3)
 1 int maxSubList1(int a[], int n)
 2 {
 3     int max = 0;
 4     int i,j,k;
 5     int thisSum;
 6     for (i = 0; i < n; ++i)
 7     {
 8         for(j = i; j < n; ++j)
 9         {
10             thisSum = 0;
11             for(k = i; k < j; k++)
12                 thisSum += a[k];
13             if(thisSum > max)
14                 max = thisSum;
15         }
16     }
17     return max;
18 }

算法2:复杂度0(n^2)

int maxSubList2(int a[], int n)
{
    int max = 0;
    int i,j;
    int thisSum;
    for (i = 0; i < n; ++i)
    {
        thisSum = 0;
        for(j = i; j < n; ++j)
        {
            thisSum += a[j];
            if(max < thisSum)
                max = thisSum;
        }
    }
    return max;
}

算法3 ,分而治之 ,复杂度O(Nlogn)

说实话,这个算法,怎么明白,听陈约姥姥讲的,听明白了算法,不知道怎么实现

// 求ab的最大值
int max(int a, int b)
{
    return a > b ? a : b;
}

// 第三个算法
int maxSubList3(int a[], int left, int right)
{
    // 如果只有一个数
    int i;
    int center = (left + right) / 2; //中点
    int leftMaxSum, rightMaxSum, lrMaxSum;

    int maxLeftSum = 0;  
    int leftSum = 0;   //跨越边界的左端值最大

    int maxRightSum = 0;
    int rightSum = 0;

    if(left == right)
        return a[left];
    leftMaxSum = maxSubList3(a, left, center);// 整个出现在输入数据的左半部的最大子序列求和 
    rightMaxSum = maxSubList3(a, center+1, right);// 整个出现在输入数据的右半部的最大子序列求和 
    lrMaxSum = max(leftMaxSum, rightMaxSum); //计算左右两个子序列求和结果的最大值

    // 横跨左右两个部分的最大子序列求和

    //从center向左处理左半边  
    
    for (i = center; i >= left; i--)
    {  
        leftSum += a[i];  
        maxLeftSum = max(maxLeftSum, leftSum);  
    } 

    for (i = center+1; i <= right; ++i)
    {
        rightSum =+ a[i];
        maxRightSum = max(maxRightSum, rightSum);
    }
    return max(lrMaxSum, maxLeftSum + maxRightSum);
}

算法4,在线测试,所谓在线就是一次便利,随搞随用 复杂度O(N)

这个算法还是比较好理解的

int maxSubList4(int A[], int N )  
{   int ThisSum, MaxSum;
    int i;
    ThisSum = MaxSum = 0;
    for( i = 0; i < N; i++ ) {
        ThisSum += A[i]; /* 向右累加 */
            if( ThisSum > MaxSum )
                MaxSum = ThisSum; /* 发现更大和则更新当前结果 */
            else if( ThisSum < 0 ) /* 如果当前子列和为负 */
                ThisSum = 0; /* 则不可能使后面的部分和增大,抛弃之 */
    }
    return MaxSum;  
}

 

 

最后提交的程序

#include "stdio.h"
#define size 100000

int maxSubList1(int a[], int n)
{
    int max = 0;
    int i,j,k;
    int thisSum;
    for (i = 0; i < n; ++i)
    {
        for(j = i; j < n; ++j)
        {
            thisSum = 0;
            for(k = i; k < j; k++)
                thisSum += a[k];
            if(thisSum > max)
                max = thisSum;
        }
    }
    return max;
}

int maxSubList2(int a[], int n)
{
    int max = 0;
    int i,j;
    int thisSum;
    for (i = 0; i < n; ++i)
    {
        thisSum = 0;
        for(j = i; j < n; ++j)
        {
            thisSum += a[j];
            if(max < thisSum)
                max = thisSum;
        }
    }
    return max;
}

// 求ab的最大值
int max(int a, int b)
{
    return a > b ? a : b;
}

// 第三个算法
int maxSubList3(int a[], int left, int right)
{
    // 如果只有一个数
    int i;
    int center = (left + right) / 2; //中点
    int leftMaxSum, rightMaxSum, lrMaxSum;

    int maxLeftSum = 0;  
    int leftSum = 0;   //跨越边界的左端值最大

    int maxRightSum = 0;
    int rightSum = 0;

    if(left == right)
        return a[left];
    leftMaxSum = maxSubList3(a, left, center);// 整个出现在输入数据的左半部的最大子序列求和 
    rightMaxSum = maxSubList3(a, center+1, right);// 整个出现在输入数据的右半部的最大子序列求和 
    lrMaxSum = max(leftMaxSum, rightMaxSum); //计算左右两个子序列求和结果的最大值

    // 横跨左右两个部分的最大子序列求和

    //从center向左处理左半边  
    
    for (i = center; i >= left; i--)
    {  
        leftSum += a[i];  
        maxLeftSum = max(maxLeftSum, leftSum);  
    } 

    for (i = center+1; i <= right; ++i)
    {
        rightSum =+ a[i];
        maxRightSum = max(maxRightSum, rightSum);
    }
    return max(lrMaxSum, maxLeftSum + maxRightSum);
}

int maxSubList4(int A[], int N )  
{   int ThisSum, MaxSum;
    int i;
    ThisSum = MaxSum = 0;
    for( i = 0; i < N; i++ ) {
        ThisSum += A[i]; /* 向右累加 */
            if( ThisSum > MaxSum )
                MaxSum = ThisSum; /* 发现更大和则更新当前结果 */
            else if( ThisSum < 0 ) /* 如果当前子列和为负 */
                ThisSum = 0; /* 则不可能使后面的部分和增大,抛弃之 */
    }
    return MaxSum;  
}
int main(int argc, char const *argv[])
{
    int i, n, a[size];
    while(scanf("%d", &n) != EOF)
    {
        for (i = 0; i < n; ++i)
        {
            scanf("%d", &a[i]);
        }
        printf("%d\n", maxSubList4(a, n));
    }
    return 0;
}

 

posted @ 2017-03-05 21:02  大波非猫  阅读(1297)  评论(0编辑  收藏  举报