首页 > 其他 > 详细

最大子段和

时间:2020-05-01 22:56:33      阅读:64      评论:0      收藏:0      [点我收藏+]

参地址https://blog.csdn.net/qq_22238021/article/details/78863701

问题定义:
对于给定序列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 }

 

最大子段和

原文:https://www.cnblogs.com/halunann/p/12814993.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!