问题描述:给定一个n(n>=1)个整数序列,求出其中最大连续子段和。例如:序列(-2,11,-4,13,-5,-2)的最大子序列和为20。其最大子序列是:(11,-4,13)
【思想】 若n=1(即序列中只有1个元素),若该元素大于0,则返回该元素;否则返回0(定义一个序列的最大连续子段和至少为0,若元素全为负数,定义其和为0);
(1)、该子序列完全落在左半部,即a[0...mid]中,采用递归求最大连续子段和maxLeftSum;
(2)、该子序列完全落在右半部,即a[mid+1...n-1]中,采用递归求最大连续子段和maxRightSum;
(3)、该子序列跨越a的中部而占据左右部分,以中间元素a[mid](假设它属于左边)为界,向左边部分和右边部分扩张,以左边为例,定义leftBorderSum=0,maxLeftBorderSum=0
让leftBorderSum从中间让左边累加,如果遇到正数就把正数加上去,并把结果赋值给maxleftBorderSum (表现形式就是如果leftBorderSum>maxLeftBorderSum说明加了个正数);
右边同样的道理。最后 maxMidSum=maxleftBorderSum+maxRightBorderSum
(4)、比较出(1)(2)(3)中所求的数那一个最大即为所求结果。
【伪代码】
maxSubSum(a, left, right){
if(left=right) Then returna[left] (值为负数返回值为0);
else{
mid=(left+right)/2;
maxLeftSum = maxSubSum(a,left,mid); //递归处理左右2部分
maxRightSum= maxSubSum(a,mid+1,right);
maxLeftBorderSum=leftBorderSum+a[i]; //从中间往左,遇到正数累加
maxRightBorderSum=rightBorderSum+a[j]; //从中间往右,遇到正数累加
maxMidSum=maxLeftBorderSum+maxRightBorderSum;
}
return max (maxLeftSum,maxRightSum,maxMidSum);
}
【代码示例】
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 5 int max(int a,int b,int c){ //求3个数中的最大值 6 int temp=(a>b)?a:b; 7 int max=(temp>c)?temp:c; 8 return max; 9 } 10 11 int maxSubSum(int a[],int left,int right){ 12 if(left==right){ 13 if(a[left]>0){ 14 return a[left]; 15 }else{ 16 return 0; 17 } 18 }else{ 19 int mid=(left+right)/2; //中间点的下标 ,向下取整 20 int maxLeftSum = maxSubSum(a,left,mid); //不跨界的情况下,左边的最大子段和 ,用递归 21 int maxRightSum= maxSubSum(a,mid+1,right);// 不跨界的情况下,右边的最大子段和 22 23 int leftBorderSum=0,maxLeftBorderSum=0; //跨边界的情况 左边界 最大左边界 24 int rightBorderSum=0,maxRighBorderSum=0; 25 for(int i=mid;i>=left;i--){ //从中间往左,遇见负数总和必然变小,不加。遇到正数,加上 26 leftBorderSum=leftBorderSum+a[i]; 27 if(leftBorderSum>maxLeftBorderSum) 28 maxLeftBorderSum=leftBorderSum; 29 } 30 31 for(int j=mid+1;j<=right;j++){ //从中间往右 32 rightBorderSum=rightBorderSum+a[j]; 33 if(rightBorderSum>maxRighBorderSum) 34 maxRighBorderSum=rightBorderSum; 35 36 } 37 38 return max(maxLeftSum,maxRightSum,maxLeftBorderSum+maxRighBorderSum); //比较3个数的最大值 39 40 41 } 42 } 43 44 int main() 45 { 46 int a[6]={-2,11,-4,13,-5,-2}; 47 printf("max=%d",maxSubSum(a,0,5));//0和5分别为数组大小为6的a数组的最左下标和最右下标 48 return 0; 49 }
【结果示例】