问题描述:子数组为数组中连续的一段序列,求最大子数组指的是找到一个非空子数组,使得它的序列和最大。即给定一个数组a[n],对于任意一对数组小标 l,r(l<=r)的非空子数组,其和记为S(l,r)=a[l]+…a[r],求出S(l,r)的最大值。
输入:
第一行输入一个整数n,第二行输入n个整数,在这n个整数中找到最大子数组
输出:
输出一个整数,即S(l,r)的最大值
解题思路:
如果用蛮力枚举的话,要枚举
n
+
C
n
2
.
n+C_n^2.
n+Cn2.
种下标 l,r组合,再求出最大子数组之和
int max=0;
for(int i=1;i<=n;i++) //这里数组a[0]不存数据
{ int s=0;
for(int j=i;j<=n;j++){
s+=a[j];
if(max<s) max=s;
}
}
printf("%d\n",max);
用分治策略则将数组二分,然后递归求解两个子数组的最大子数组,得到S1,S2,再合并子问题得到S_max,关键在于求跨中点的最大子数组S3,S_max=max{S1,S2,S3}
mid=n/2,S3求和时一定包括a[mid],a[mid+1],则S3可以分为两部分的和,以a[mid]结尾的最大子数组之和,以a[mid+1]开头的最大子数组之和
参考下列代码:
int max(int a,int b,int c);
int CrossingSubArray(int a[],int left,int mid,int right);
int MaxSubArray(int a[],int left,int right){
if(left>=right) return 0;
else{
int S1,S2,S3;
int mid=(left+right)/2;
S1=MaxSubArray(a,left,mid);
S2=MaxSubArray(a,mid+1,right);
S3=CrossingSubArray(a,left,mid,right);
return max(S1,S2,S3);
}
}
int CrossingSubArray(int a[],int left,int mid,int right){
int L=0,SL=0;
for(int i=mid;i>=left;i--) //数组下标为0的位置不存数据
{ SL+=a[i];
if(SL>L) L=SL; }
int R=0,SR=0;
for(int i=mid+1;i<=right;i++){
SR+=a[i]; if(SR>R) R=SR;
}
return L+R;
}
int max(int a,int b,int c){
a=a>b?a:b;
return a>c?a:c;
}
蛮力枚举的时间复杂度为O(n^2)
分而治之的时间复杂度为O(nlogn)