寻找最大子数组问题即为寻求数组中连续的最大子数组和。我尝试了三种求解办法:分治法、暴力求解法和动态规划。个人觉得分治法实现起来较为困难,而暴力求解法虽然时间复杂度较大,但是实现起来简单呐,然后动态规划实在是让人心旷神怡的解决办法,强烈推荐。
暴力求解法:
暴力求解法就是算出所有可能的子数组和,比较大小,得出最大子数组。
下面时暴力求解法源码:
int findMaxSubarray__(int a[],int n,int& left,int& right){
int i,j;
int sum,maxsum=INT_MIN;
for(i=0;i<n;i++){
sum=0;
for(j=i;j<n;j++){
sum+=a[j];
if(sum>maxsum){
maxsum=sum;
left=i;
right=j;
}
}
}
return maxsum;
}
分治法:
分治法是把最大子数组和问题分解为:求左边最大子数组,求右边最大子数组和求跨越中间的最大子数组。其中,求左边最大子数组和求右边最大子数组都是用递归求解,而中间最大子数组则是从中间开始,分别向左边和右边求最大和,之后加到一起即可。最后,比较左边最大子数组和、右边最大子数组和、中间最大子数组和,取最大即可。
下面是分治法源码:
int findMaxSubarray_(int a[],int l,int r,int& left,int& right){
if(l<r){
int mid=(l+r)/2;
int ll,lr;
int suml=findMaxSubarray_(a,l,mid,ll,lr);
int rl,rr;
int sumr=findMaxSubarray_(a,mid+1,r,rl,rr);
int sumc=0;
int maxLeft=INT_MIN;
int ml,mr;
int i;
for(i=mid;i>=l;i--){
sumc+=a[i];
if(sumc>maxLeft){
maxLeft=sumc;
ml=i;
}
}
int maxRight=INT_MIN;
sumc=0;
for(i=mid+1;i<=r;i++){
sumc+=a[i];
if(sumc>maxRight){
maxRight=sumc;
mr=i;
}
}
sumc=maxLeft+maxRight;
if(suml<sumr){
if(sumr<sumc){
left=ml;
right=mr;
return sumc;
}
else{
left=rl;
right=rr;
return sumr;
}
}
else{
if(suml<sumc){
left=ml;
right=mr;
return sumc;
}
else{
left=ll;
right=lr;
return suml;
}
}
}
else{
left=l;
right=r;
return a[l];
}
}
动态规划:
动态规划是用maxsum表示最大子数组,然后从0到n-1进行累加,如果前值小于0,则前值置0之后再进行累加,否则就直接累加。每次累加都和maxsum比较大小,始终保持maxsum是两者中的最大值。
下面是动态规划法源码:
int findMaxSubarray___(int a[],int n,int& left,int& right){
int cursum=a[0];
int maxsum=a[0];
int i;
left=0;
right=0;
for(i=1;i<n;i++){
if(cursum<0){
cursum=0;
left=i;
right=i;
}
cursum+=a[i];
if(cursum>maxsum){
maxsum=cursum;
right=i;
}
}
return maxsum;
}
这次最大的收获是认识了int &这个类型,其中&表示引用,可以进行值的传递,用起来非常方便。下面的链接详述了int &的用法及它和int、int *的区别。
http://blog.youkuaiyun.com/willian0621/article/details/12838157