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种一样。