最大和子數組是數組中和最大的子數組,又名最大和子序列。子數組是數組中連續的n個元素,比如a2,a3,a4就是一個長度為3的子數組。顧名思義求最大和子數組就是要求取和最大的子數組。
n個元素的數組包含n個長度為1的子數組:{a0},{a1},…{an-1};
n個元素的數組包含n-1個長度為2的子數組:{a0,a1},{a1,a2},{an-2,an-1};
………………………………………………………………………………………………
n個元素的數組包含1個長度為n的子數組:{a0,a1,…,an-1};
所以,一個長度為n的數組包含的子數組個數為n+(n-1)+…+1=n*(n-1)/2。
第一反應就是蠻力法,窮舉數組所有子數組的和並求出和的最大值。這種方法簡單直觀容易想到,具體又有幾種不同的思路。第一種方法是先求出所有長度為1的子數組的和,再求長度為2的子數組的和,以此類推,直到求出所有長度為n的子數組的和,並在求子數組和的過程中記錄和的最大值。偽代碼如下:
maxSum=arr[0];//maxSum記錄最大子數組和
for(i=1,i<=n;i++){//子數組長度
for(j=0;j<n;j++){//子數組開始的位置(數組下標)
sum=0;//sum記錄當前子數組和
for(k=j;k<n&&k<j+i;k++){//求和
sum+=arr[k];
}
if(sum>maxSum) maxSum=sum;
}
}
第二種方法是先求所有以a[0]開始的子數組的和,再求所有以a[1]開始的子數組的和,以此類推,直到最后求出所有以a[n-1]開始的子數組的和,並在求子數組和的過程中記錄和的最大值。偽代碼如下:
int maxSubArraySum(int *arr,int n){
int i,j,maxSum=arr[0],sum;
for(i=0;i<n;i++){//子數組開始位置
sum=0;
for(j=i;j<n;j++){//以arr[i]開始的不同長度的子數組的和,求和是一個遞進過程
sum+=arr[j];
if(sum>maxSum) maxSum=sum;
}
}
return maxSum;
}
蠻力法雖然可以求得問題的解,但蠻力法通常不是我們所希望的,其時間復雜度大。我們希望找到一 種更有效的方法來解決該問題,所以需要思考問題具有的特征,拿到問題就開始寫代碼是最忌諱的,代碼前需要三思。最大和子數組一定以數組中的某個元素a[i](0<=i<n)結束,那么我們可以先分別求出以每個元素結尾的子數組的最大和,其中的最大值就是所求的最大子數組和。后一個元素的求和需要用到前一個元素的結果,遞推公式為maxSumEnd[i]=max{maxSumEnd[i-1]+a[i],a[i]},代碼如下:
int maxSumArraySumD(int *arr,int n){
int i,maxSum=arr[0];
int *maxSumEnd;
maxSumEnd=(int*)malloc(sizeof(int)*n);
maxSumEnd[0]=arr[0];
for(i=1;i<n;i++){
if(maxSumEnd[i-1]+arr[i]>arr[i])
maxSumEnd[i]=maxSumEnd[i-1]+arr[i];
else
maxSumEnd[i]=arr[i];
if(maxSumEnd[i]>maxSum)
maxSum=maxSumEnd[i];
}
free(maxSumEnd);
return maxSum;
}
這道題目如果我們能聯想到一些數學知識就可以得到更簡潔的答案,優秀的程序猿一定具有很厚的數學基礎和敏捷的數學思維,但有很厚數學基礎和敏捷數學思維的人不一定就是程序猿,歷史證明無數優秀的數學家都變成了經濟學家,計算機這個專業學到后面也就剩英語和數學了,華爾街那幫吸血鬼個個都是數學怪才。
一個數加上一個負數和會變小,一個數加上0和保持不變,一個數只有加上一個正數和才會變大。如果最大和子數組為a[i],a[j],a[k],那么一定有a[i]+a[j]>0,如果a[i]+a[j]<=0,那么最大和子數組就是a[k]。因此,我們可以從a[0]累加求和,只要累加的和大於0就繼續向后累加,如果累加的和小於0,那就舍棄掉,從下一個元素從新開始累加,並在累加過程中記錄和的最大值。代碼如下:
int maxSubArraySum(int *arr,int n){
int i,maxSum=arr[0],sum=0;
for(i=0;i<n;i++){
sum+=arr[i];
if(sum>maxSum){ //記錄最大累加和
maxSum=sum;
}
if(sum<0){//累加和小於0舍棄
sum=0;
}
}
return maxSum;
}
或許還需給出最大和子數組,那么要在求最大和子數組的過程中記錄最大和子數組的起始位置。代碼如下:
int maxSubArraySumPos(int *arr,int n){
int i,maxSum=arr[0],sum=0;
int start=0,end=0,s=0,e=0;
for(i=0;i<n;i++){
sum+=arr[i];
if(sum>maxSum){
maxSum=sum;
e=i;
start=s;
end=e;
}
if(sum<0){
sum=0;
s=i+1;
e=i+1;
}
}
printf("start=%d end=%d\n",start,end);
return maxSum;
}
羅馬之路不順暢,大俠們不要吝嗇自己的武功秘籍,評論區為各位大俠所留。