算法设计——最大子段和
参地址https://blog.csdn.net/qq_22238021/article/details/78863701
问题定义:
对于给定序列a1,a2,a3……an,寻找它的某个连续子段,使得其和最大。
如( -2,11,-4,13,-5,-2 )最大子段是{ 11,-4,13 }其和为20。
对于给定序列a1,a2,a3……an,寻找它的某个连续子段,使得其和最大。
如( -2,11,-4,13,-5,-2 )最大子段是{ 11,-4,13 }其和为20。
以下提供三种方法:枚举法、分治法、动态规划法,具体分析在代码的注释中。
枚举法,复杂度:O(n^2)
#include<iostream>
using namespace std;
//如( -2,11,-4,13,-5,-2 )最大子段是{ 11,-4,13 }其和为20
//枚举:分别从0~n-1作为起点,一直加到最后,寻找最大值
//时间复杂度:O(n^2)
int MaxSum(int &besti,int &bestj,int arr[],int n){
int max=arr[0]; //那么最大值一定>=目前的max
int sum;
for(int i=0;i<n;i++){ //枚举,依次从arr[i]开始求和
sum=0;
for(int j=i;j<n;j++){ //从arr[i]加到arr[n-1],寻找最大值
sum+=arr[j];
if(max<sum){
max=sum;
besti=i;
bestj=j;
}
}
}
return max;
}
int main(){
int arr[6]={-2,11,-4,13,-5,-2};
int n=6;
for(int i=0;i<n;i++)
cout<<arr[i]<<" ";
cout<<endl;
int besti,bestj,maxSum;
maxSum=MaxSum(besti,bestj,arr,n);
cout<<besti<<" "<<bestj<<endl;
for(int i=besti;i<=bestj;i++)
cout<<arr[i]<<" ";
cout<<endl<<"maxSum="<<maxSum<<endl;
system("pause");
return 0;
}
分治法,复杂度:O(nlogn)
#include<iostream> using namespace std; //如( -2,11,-4,13,-5,-2 )最大子段是{ 11,-4,13 }其和为20 //分治:将arr[1:n]分成arr[1:n/2]和arr[n/2+1:n],那么最大值可能有以下三种情况 //1:maxSum在arr[1:n/2]中 //2:maxSum在arr[n/2+1:n]中 //3:maxSum在arr[i:j]中,并且1<=i<=n/2,n/2+1<=j<=n; //时间复杂度:递归方程,T(n)=2T(n/2)+O(n),结果为O(nlogn) int MaxSumHelp(int left,int right,int arr[]){ if(left==right){ //边界条件,不要忘记! return arr[left]>0?arr[left]:0; } int center=(left+right)/2; //获得1、2情况的最大值 int leftMaxSum=MaxSumHelp(left,center,arr); int rightMaxSum=MaxSumHelp(center+1,right,arr); //获得3情况的最大值,需要从center(向左),center+1(向右),分别向两边计算,即固定了起点 int lefts=0,s1=arr[center]; //此时一定:s1<=最大值 for(int i=center;i>=left;i--){ lefts+=arr[i]; if(s1<lefts){ s1=lefts; //s1用于记录以arr[center]为边的最大值 } } int rights=0,s2=arr[center+1]; for(int i=center+1;i<=right;i++){ rights+=arr[i]; if(s2<rights){ s2=rights; //s2用于记录以arr[center+1]为边的最大值 } } int sum=s1+s2; //比较3种情况的sum,获得本次的最大和 if(sum<leftMaxSum){ sum=leftMaxSum; } if(sum<rightMaxSum){ sum=rightMaxSum; } return sum; } int MaxSum(int n,int arr[]){ return MaxSumHelp(0,n-1,arr); } int main(){ int arr[6]={-2,11,-4,13,-5,-2}; int n=6; cout<<MaxSum(n,arr)<<endl; system("pause"); return 0; }
动态规划,复杂度:O(n)
1 #include<iostream> 2 using namespace std; 3 4 //如( -2,11,-4,13,-5,-2 )最大子段是{ 11,-4,13 }其和为20 5 //动态规划: 6 //假设b[j]表示arr[i:j]的最大和,即以a[j]为终点的最大值,不管a[j]是否是负数,必须包含它 7 //那么如果b[j-1]>0,b[j]=b[j-1]+arr[j],否则b[j]=arr[j], 8 //其中由max来记录曾经有过的最大和,那么一次循环结束后,就能得到最大子段和 9 //动态规划递推式: 10 11 int MaxSum(int n,int arr[]){ 12 int b=0,max=arr[0]; //此刻一定有:max<=最终最大和,不要之间设置成0,因为所给数组可能全部<0 13 for(int i=0;i<n;i++){ 14 if(b>0) 15 b+=arr[i]; 16 else 17 b=arr[i]; 18 19 if(max<b) 20 max=b; 21 } 22 return max; 23 } 24 25 int main(){ 26 int arr[6]={-2,11,-4,13,-5,-2}; 27 int n=6; 28 29 cout<<MaxSum(n,arr)<<endl; 30 31 system("pause"); 32 return 0; 33 }

浙公网安备 33010602011771号