最大连续子段和

最大连续子段和

•          给定长度为n的整数序列,a[1...n], 求[1,n]某个子区间[i,j]使得a[i]+…+a[j]和最大,或者求出最大的这个和。例如(-2,11,-4,13,-5,2)的最大子段和为20,所求子区间为[2,4]。

 

•       穷举法(3次for循环)

           第1次for循环,遍历数组所有数字,即确定子段和的首个数字;

          第2次for循环,遍历数个数字之后的所有数字,即确定字段和的最后一个数字;

          第3次for循环,遍历首个数字与最后一个数字,对之间所有数字求和。

 1 int maxSum(int a[], int num, int &start, int &end){  2     int localSum= MINNUM;  3     for (int i = 0; i < num; i++){  4         for (int j = i; j < num; j++){  5             int thisSum = 0;  6             for (int k = i; k <= j; k++){  7                 thisSum += a[k];  8  }  9             if (thisSum > localSum){ 10                 start = i; 11                 end = j; 12                 localSum = thisSum; 13  } 14  } 15  } 16     return localSum; 17 }

•       穷举优化法(2次for循环)

           第1次for循环,遍历数组所有数字,即确定子段和的首个数字;

          第2次for循环,遍历数个数字之后的所有数字,即确定字段和的最后一个数字;

          用thisSum记录不同结尾数字对应的子段和,进而比较获得对应首个数字的最大子段和

 1 int maxSum(int a[], int num, int* start, int* end){  2     int localSum= 0;  3     for (int i = 0; i < num; i++){  4         int thisSum = 0;  5         for (int k = i; k < num; k++){  6             thisSum += a[k];  7             if (thisSum > localSum){  8                 *start = i;  9                 *end = k; 10                 localSum = thisSum; 11  } 12  } 13  } 14     return localSum; 15 }

•       分治策略

           将初始最大子段和问题分解为两个相同的子问题;

    •     分别对相同的子段求解最大子段和;

    •     合并子问题的解,获得原问题的解。

             最大子段和位于左子段

             最大子段和位于右子段

             最大子段和的首数字位于左子段,尾数字位于右子段

 1 int maxSum(int a[], int left, int right){  2     int localSum = 0;  3     if (left == right) localSum = (a[left] > 0 ? a[left] : 0);  4     else{  5         int mid = (left + right)/2;  6         int leftSum = maxSum(a, left, mid);  7         int rightSum = maxSum(a, mid + 1, right);  8         int sum1 = 0;     int lefts = 0;  9         for (int i = mid; i >= left; i--){ 10             lefts += a[i]; 11             if (lefts > sum1)   sum1 = lefts; 12  } 13         int sum2 = 0;  int rights = 0; 14         for (int i = mid + 1; i <= right; i++){ 15             rights += a[i]; 16             if (rights > sum2)  sum2 = rights; 17  } 18         localSum = sum1 + sum2; 19         if (localSum < leftSum) localSum = leftSum; 20         if (localSum < rightSum) localSum = rightSum; 21     }            return localSum; 22 }

       动态规划

         令b[j]表示以位置 j 为终点的所有子区间中和最大的一个

    子问题:如j为终点的最大子区间包含了位置j-1,则以j-1为终点的最大子区间必然包括在其中

        如果b[j-1] >0, 那么显然b[j] = b[j-1] + a[j],用之前最大的一个加上a[j]即可,因为a[j]必须包含

        如果b[j-1]<=0,那么b[j] = a[j] ,因为既然最大,前面的负数必然不能使你更大

 1 int maxSum(int a[], int num)  2 {  3     int localSum = 0;  4     int b = 0;  5     for (int i = 0; i < num; i++)  6  {  7         if (b > 0)  8             b += a[i];  9         else 
10             b = a[i]; 11         if (b > localSum) 12              localSum = b; 13  } 14     return localSum; 15 }

   算法效率分析

         穷举法       O(n3)

        穷举优化法   O(n2)

        分治法       O(nlogn)

        动态规划法   O(n)

  附带一些完整代码:

 1 //动态规划
 2 # include<stdio.h>
 3 # include<stdio.h>
 4 int maxsum(int a[],int num)  5 {  6     int localsum=a[0];  7     int b=0;  8     for(int i=0;i<num;i++)  9  { 10         if(b>0) 11             b += a[i]; 12         else
13             b=a[i]; 14         if(b>localsum) 15             localsum=b; 16  } 17     return localsum; 18 } 19 int main() 20 { 21     int a[15]; 22     int n,i; 23     while(scanf("%d",&n)!=EOF){ 24         for(i=0;i<n;i++) 25             scanf("%d",&a[i]); 26         printf("%d\n",maxsum(a,n)); 27  } 28     return 0; 29 } 30 //分治算法
31 # include<stdio.h>
32 int maxsum(int a[],int left,int right) 33 { 34     int localsum=0,i; 35     if(left==right) 36         localsum=(a[left]>0)?a[left]:0; 37     else{ 38         int mid=(left+right)/2; 39         int leftsum=maxsum(a,left,mid); 40         int rightsum=maxsum(a,mid+1,right); 41         int sum1=0; int lefts=0; 42         for(i=mid;i>=left;i--){ 43             lefts+=a[i]; 44             if(lefts>sum1) sum1=lefts; 45  } 46         int sum2=0; int rights=0; 47         for(i=mid+1;i<=right;i++){ 48             rights+=a[i]; 49             if(rights>sum2) sum2=rights; 50  } 51         localsum=sum1+sum2; 52         if(localsum<leftsum) localsum=leftsum; 53         if(localsum<rightsum) localsum=rightsum; 54  } 55     return localsum; 56 } 57 int main() 58 { 59     int a[15]; 60     int n,temp,i,j,k,max; 61     while(scanf("%d",&n)!=EOF){ 62         for(i=0;i<n;i++) 63             scanf("%d",&a[i]); 64         printf("%d\n",maxsum(a,0,n-1)); 65  } 66     return 0; 67 } 68 
69 //暴力解法
70 # include<stdio.h>
71 int main() 72 { 73     int a[15]; 74     int n,temp,i,j,k,max; 75     while(scanf("%d",&n)!=EOF){ 76         for(i=0;i<n;i++) 77             scanf("%d",&a[i]); 78         max=0; 79         for(i=0;i<n;i++) 80  { 81             for(j=i;j<n;j++) 82  { 83                 int temp=0; 84                 for(k=i;k<=j;k++) 85                     temp+=a[k]; 86                 if(temp>max) 87                     max=temp; 88  } 89             
90  } 91         printf("%d\n",max); 92  } 93     return 0; 94 }
View Code

 

你可能感兴趣的:(最大连续子段和)