3.求子数组的最大和

问题:给出一个数组,元素有正有负,数组中连续的1个或者多个数组成1个子数组,每个子数组有1个和,求所有子数组和值的最大值,时间复杂度为O(n)

解: 一:可以用穷举的方法求出这个最大值,只是时间复杂度是O(n^3),这中方法的代码如下

int  dphe(int a[],int len)
{
    int i,j;
    int **he=new int*[len];

    for(i=0;i<len;i++)
        *(he+i)=new int[len]();

    for(i=0;i<len;i++)
        for(j=0;j<len;j++)
                he[i][j]=0;

    int length;

    for(length=0;length<len;length++)
     for(i=0;i<len-length;i++)
        for(j=i;j<=i+length;j++)
            he[i][i+length]+=a[j];
        
        
    int max=INT_MIN;
    for(i=0;i<len;i++)
        for(j=0;j<len;j++)
            if(he[i][j]>=max)
                max=he[i][j];

    for(i=0;i<len;i++)
        delete [] *(he+i);
    delete he;
    return max;
}

这中方法没什么技巧,穷举所有的值。

二: 观察数组可以发现,因为是要求连续的元素组成子数组,假设给定的数组是A[1,N],最后假设和最大的子数组是A[p,q],其中1<=p<=q<=N,那么我们可以得到,A[1,p-1]这个子数组的和一定是负值,否则A[1,p-1]+A[p,q]>A[p,q]就不满足A[p,q]是子数组最大的了。所以,我们可以对A进行遍历,当遇到子数组的和是负值时,就可以抛弃整个子数组了,同时要记下前面子数组的最大值,下面是用栈写的,规则如下

1。每个元素顺序入栈,设置2个变量sum和max,sum记录在栈中的元素的总和,max记录到目前元素为止最大的子数组的和

2。元素入栈后计算sum,若sum<0,则栈中元素全部出栈;若sum>0,则将sum和max对比,若sum>max,则更新max,否则max不变,

代码如下,测试部分随即生成元素,并和穷举法的结果比较,最后结果都一样。

/*
     求子数组的和,现用DP做
 */

#include<iostream>
#include<climits>
#include<cstdlib>
#include<time.h>
using namespace std;

int  dphe(int a[],int len)
{
    int i,j;
    int **he=new int*[len];

    for(i=0;i<len;i++)
        *(he+i)=new int[len]();

    for(i=0;i<len;i++)
        for(j=0;j<len;j++)
                he[i][j]=0;

    int length;

    for(length=0;length<len;length++)
     for(i=0;i<len-length;i++)
        for(j=i;j<=i+length;j++)
            he[i][i+length]+=a[j];
        
        
    int max=INT_MIN;
    for(i=0;i<len;i++)
        for(j=0;j<len;j++)
            if(he[i][j]>=max)
                max=he[i][j];

    for(i=0;i<len;i++)
        delete [] *(he+i);
    delete he;
    return max;
}

/*
     下面用栈做,规则如下
     1.元素顺序入栈,保存2个变量sum和max,sum代表整个栈中元素的总和,sum代表到目前元素为止前面最大的子数组的和
     2.若sum<0,则清空整个栈
     3.若sum>max,则更新sum
*/

typedef int DataType;
#define MAX 100
typedef struct
{
    DataType data[MAX];
    int top;
}Stack;

Stack* init_stack(void)
{
    Stack* s=new Stack;
    if(s)
        s->top=-1;
    return s;
}

bool empty_stack(Stack* s)
{
    if(s->top==-1)
        return true;
    return false;
}

bool full_stack(Stack* s)
{
    if(s->top==MAX-1)
        return true;
    return false;
}

void push_stack(Stack* s,DataType value)
{
    if(full_stack(s))    
        return ;
    s->top++;
    s->data[s->top]=value;
}

void pop_stack(Stack* s,DataType *value)
{
    if(empty_stack(s))
        return ;
    *value=s->data[s->top];
    s->top--;
}

void clear_stack(Stack* s)
{
    int value;
    while(!empty_stack(s))
        pop_stack(s,&value);
}

void free_stack(Stack* s)
{
    delete s;
}


int he(int a[],int length)
{
    int i;
    Stack* s;
    int sum=0,max=INT_MIN;

    s=init_stack();
    for(i=0;i<length;i++)
    {
        push_stack(s,a[i]);
        sum=sum+a[i];
        if(sum<=0)
        {
            clear_stack(s);
            sum=0;
        }
        else // sum>0
        {
            if(sum>max)
                max=sum;
        }
    }
    return max;
    free_stack(s);
}    

int main(void)
{
    int b[]={3,-5,2,-4,7,-2,10,1};
    int c[]={-1,0,2,-1,0,4,2,-1};
    
    int a[8];
    int i,j;

    //比较10次
    for(j=1;j<=10;j++)
    {
        srand(time(NULL));
        for(i=0;i<8;i++)
            a[i]=rand()%200-100; //随即产生-100-100的数
        for(i=0;i<8;i++)
            cout<<a[i]<<" ";

        cout<<"穷举和="<<dphe(a,8)<<" ";
        cout<<"栈和="<<he(a,8)<<endl;
        sleep(1);
    }
    return 0;
}

三: 可以对上面代码进行精简,不用栈,对数组遍历就行。代码如下

int he2(int a[],int length)
{
    int i,j;
    int sum=0,max=INT_MIN;


    for(i=0;i<length;i++)
    {
        sum+=a[i];
        if(sum<=0)
            sum=0;
        else if(sum>max)
            max=sum;    
    }
    return max;
}

同样可以测试,结果于上面2种一样。

 

 

 

posted on 2013-07-18 22:33  紫金树下  阅读(212)  评论(0编辑  收藏  举报