结对(求数组的最大子数组和)

题目:

  返回一个整数数组中最大子数组的和。

要求:

  输入一个整形数组,数组里有正数也有负数。

  数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。

  如果数组A[0]……A[j-1]首尾相邻,允许A[i-1], …… A[n-1], A[0]……A[j-1]之和最大。

  同时返回最大子数组的位置。

  求所有子数组的和的最大值。

(我主要负责程序分析,代码编程;张金负责代码复审,代码测试计划。)

 

思路:

  与第一次的不同之处,只在于首尾相连,构成了一个环。思路差不多,我们构造了三个数组:(A)arr[]为原数组;(B)Max[]保存以每个元素为头的所有子数组的和的最大值;(C)arrCopy[]将原数组头尾相连构造的新的一维数组。它们的关系如下:

max[0]为{arr[0]、arr[0]+arr[1]、...、arr[0]+arr[1]+...+arr[n-1]+arr[n]}中的最大值;

max[1]为{arr[1]、arr[1]+arr[2]、...、arr[1]+arr[2]+...+arr[n]+arr[1]}中的最大值;

......

max[n-1]为{arr[n-1]、arr[n-1]+arr[n]、...、arr[n-1]+arr[n]+...+arr[n-3]+arr[n-2]}中的最大值;

max[n]为{arr[n]、arr[n]+arr[1]、...、arr[n]+arr[1]+...+arr[n-2]+arr[n-1]}中的最大值。再比较max数组,从中找到最大值。

arrCopy[]为{arr[1]、arr[2]、...、arr[n]、arr[1]、...、arr[n-1]}这样的一个数组,它的的作用则是标记子数组的位置。

<span style="font-family: Microsoft YaHei; font-size: 16px;">#include<iostream.h>

#include<stdlib.h>

#define AMOUNT 100

int main()

{

    int arr[AMOUNT];

    int arrCopy[AMOUNT];

    int max[AMOUNT];

    int i,j;

    int n;

    int head,rear;      //子数组的开始,结束

    int mount,amount;

    cout<<"input mount: ";

    cin>>mount;

    while(mount<=0)

    {

    cout<<"illegal input! Again :";

    cin>>mount;

    }

    amount=2*mount-1;

    for(i=0;i<mount;i++)

    {

    try

    {

            n=rand()%2;

            if(n==0)

        {

        arr[i]=rand()%100;

        arrCopy[i]=arr[i];

        max[i]=arr[i];

        }

        else

        {

        arr[i]=-rand()%100;

        arrCopy[i]=arr[i];

        max[i]=arr[i];

        }

        }

    catch(long int e)

    {

        cout<<"Long Inter=ger Exception!"<<endl;

        }

    }

    for(i=0;i<mount;i++)

    {

    cout<<arr[i]<<"  ";

    if((i+1)%10==0)

    {

        cout<<endl;

    }

    }

    for(i=mount;i<amount;i++)

    {

    arr[i]=arr[i-mount];

    arrCopy[i]=arr[i];

    }

    for(j=0;j<mount;j++)

    {

        for(i=j+1;i<j+mount;i++)

        {  

        arr[j]=arr[j]+arr[i];

        if(max[j]<arr[j])

        {

        max[j]=arr[j];

        rear=i+1;

        if(rear>mount)

        {

            rear=rear-mount;

        }          

        }

        }

    }

    for(i=0;i<mount;i++)

    {

        if(max[0]<max[i])

    {

            max[0]=max[i];

        head=i+1;

    }  

    }

    cout<<endl;

    cout<<"从第"<<head<<"个数"<<arrCopy[head-1]<<"开始"<<endl;

    cout<<"到第"<<rear<<"个数"<<arrCopy[rear-1]<<"结束"<<endl;

    cout<<"子数组和的最大值为: "<<max[0]<<endl;

    return 0;

}               

</span>

运行结果:

(1)首先由于没有仔细的考虑,在提示输入数组长度的时候随意输了负数,导致程序不能正常执行,经过修改,能对不符合的数据类型发出错误提示,并且重新输入。

 

(2)有图可以看到,定义的数组长度为5,和最大的子数组是由第5个数循环至第1个数组成的,但却显示的是arrCopy[]数组中的第6个数,位置不正确。

(3)经过修改,能正确找到环的结束位置。

 

(4)但是我们自己手动输入的数都很小,所以最后改动:只输入数组长度(截图测试为10),数值随机产生。

总结:

  看到题目最先想到的是数据结构中的链表结构,但是很快就把这个思路放弃,感觉用链表比较麻烦,听了课上三位同学的思路,大家的观点其实都是把数组构成一个环状结构,或者构成一个新的一维数组,接着就跟第一次求最大和一样。开始犯难的是在怎么确定子数组的起始元素和结尾元素上,下标的记录是很关键的,因为在我们的算法中,运用递归会不断覆盖原数组的值,造成所有子数组求完和之后,原数组的值发生了改变,而无法返回最大子数组的位置,既然如此,能像到的方法就是把子数组复制一遍,最后定位时可以使用。最后还是数据测试的问题,手动输入具有很大的主观意识,所以还是使用随机数测试比较能发现问题。

  感觉现在能解决一些问题了,但方法还是想初学者那般,很多类似时间、空间复杂度那些都没有考虑。

原文地址:https://www.cnblogs.com/xiaojin123/p/4376517.html