题目:一个有N个整数元素的一维数组A[0...n-1]这个数组当然有很多子数组,那么子数组之和最大值是多少?
解答:求子数组之和最大,这里是连续的子数组,如果一个数为负数,数组之和会减少,记住最大值,只要数组之和没有小于0就可以继续累加,比如{-2,3,-1,9},3到-1子数组之和减小了,但是没有小于0,可以继续累加下一个数9,就可以得到最大和3-1+9。如果子数组之和小于0了,必须重新开始累加。
int Max_array(int *a,int n)
{
if(a==NULL||n<=0)
{
cout<<"error";
return 0;
}
int sum=0,max=a[0];
for(int i=0;i<n;i++)
{
sum+=a[i];
if(max<sum)
max=sum;
if(sum<0)
sum=0;
}
return max;
}
以上程序时间复杂度为O(N),只遍历了数组一遍。
拓展:
1.如果数组A[0..n-1]首位相连,也就是允许找到一段数字(A[i]...A[n-1],A[0]...A[j]),使其和最大,怎么办?
解答:分两种情况讨论:
(1)不跨越A[n-1],A[0],就是上题的解法;
(2)跨越A[n-1],A[0]。
对于(2)跨越A[n-1],A[0]其实就是从某个位置i开始到n-1,在从0开始到j,即A[i]...A[n-1]A[0]...A[j],可以求从某个位置到结尾的最大值,和从开头到某个位置的最大值。
int Max_array(int *a,int n)
{
if(a==NULL||n<=0)
{
cout<<"error";
return 0;
}
int sum=0,max=a[0];
for(int i=0;i<n;i++)
{
sum+=a[i];
if(max<sum)
max=sum;
if(sum<0)
sum=0;
}
return max;
}
int Max_contain(int *a,int n)
{
if(a==NULL||n<=0)
{
cout<<"error";
return 0;
}
int max1=a[0];
int max2=a[n-1];
int sum=0;
for(int i=0;i<n;i++)
{
sum+=a[i];
if(sum>max1)
max1=sum;
if(sum<=0)
break;
}
sum=0;
for(int j=n-1;j>i;j--)
{
sum+=a[j];
if(sum>max2)
max2=sum;
if(sum<=0)
break;
}
return max1+max2;
}
int main()
{
int a[]={3,2,-6,1,-3,6,7};
cout<<(Max_array(a,7)>Max_contain(a,7)?Max_array(a,7):Max_contain(a,7))<<endl;
return 0;
}
2.如果题目要求同时返回最大子数组的位置,算法该如何改变,还能保证O(N)时间复杂度?
解答:可以设置连个变量保存开始位置和结束位置,只有当max<sum时,才需要调整结束位置;只有当sum<0时可能需要调整开始位置,先记录这个位置。
int Max_array(int *a,int n,int &start,int &end)
{
if(a==NULL||n<=0)
{
cout<<"error";
return 0;
}
start=end=0;
int left=0;
int sum=0,max=a[0];
for(int i=0;i<n;i++)
{
sum+=a[i];
if(max<sum)
{
max=sum;
start=left;
end=i;
}
if(sum<0)
{
sum=0;
left=i+1;
}
}
return max;
}