最大子段和

来源:互联网 发布:网络社交平台英文 编辑:程序博客网 时间:2024/06/04 17:55
public class MaxSegmentSum {

/*
给定由n个整数组成的序列a[1],a[2],a[3]......a[n],求该序列形如a[i]+a[i+1]+...+a[j]的子段和的
最大值,当所有参数均为负数时定义其最大子段和为0。故所求的最优值为:

max{0,a[i]+a[i+1]+...+a[j]},1<=i<=j<=n
例如:(a1,a2,a3,a4,a5,a6)=(-2,11,-4,13,-5,-2)时,最大子段和为20。


 */

    
/*最大子段和的简单算法
从这个算法来看,它所需的时间为O(n^3)
*/    
    public static int getMaxSegmentSumOne(int[] array){
        int n=array.length;
        int besti=0,bestj=0;
        int sum=0;
        for(int i=0;i<n;i++){
            for(int j=i;j<n;j++){
                int thisSum=0;
                for(int k=i;k<=j;k++)
                    thisSum+=array[k];
                if(thisSum>sum){
                    sum=thisSum;
                    besti=i;
                    bestj=j;
                }
            }
        }
        System.out.println("数组第"+(besti+1)+"个到"+(bestj+1)+"个数最大,最大和为"+sum);
        return sum;
    }
    
/*
(a[i]+a[i+1]+...+a[j])=a[j]+(a[i]+a[i+1]+...+a[j-1])    
上述只需O(n^2)
*/    
    public static int getMaxSegmentSumTwo(int[] array){
        int n=array.length;
        int besti=0,bestj=0;
        int sum=0;
        for(int i=0;i<n;i++){
           int thisSum=0;
           for(int j=i;j<n;j++){
               thisSum+=array[j];
               if(thisSum>sum){
                   sum=thisSum;
                   besti=i;
                   bestj=j;
               }
           }
           
        }
        
        System.out.println("数组第"+(besti+1)+"个到"+(bestj+1)+"个数最大,最大和为"+sum);
        return sum;
    }
    
/*
最大子段和的分治算法
我们可以将a[1:n]分为a[1:n/2]和a[n/2+1:n],分别求出这两段的最大子段和
(1)a[1:n]的最大子段和与a[1:n/2]的最大子段和
(2)a[1:n]的最大子段和与a[n/2+1:n]的最大子段和
(3)a[1:n]的最大子段和与a[i]+a[i+1]...a[j],且1<=i<=n/2,n/2+1<=j<=n

对应的时间复杂度T(n)
T(n)=2T(n/2)+O(n),故时间复杂度为T(n)=O(nlogn)
*/    
    
    public static int getMaxSegmentSumThree(int[] array,int left,int right){//此时可以为array[left],也可以为array[right]
        
        
        //System.out.println("left="+left+"  right="+right);
        int sum=0;
        if(left==right){
          //System.out.println("相等了="+left);
          sum=array[left]>0?array[left]:0;
        }else{
          int center=(left+right)/2;
          int leftsum=getMaxSegmentSumThree(array,left,center);
          int rightsum=getMaxSegmentSumThree(array,center+1,right);
          
          int s1=0;
          int lefts=0;
          for(int i=center;i>=left;i--){
            lefts+=array[i];
            if(lefts>s1){
                s1=lefts;
            }  
          }
          
          int s2=0;
          int rights=0;
          for(int i=center+1;i<=right;i++){
              rights+=array[i];
              if(rights>s2){
                  s2=rights;
              }
          }
          sum=s1+s2;
          if(sum<leftsum)
              sum=leftsum;
          if(sum<rightsum)
              sum=rightsum;      
        }
        return sum;
    }

/*
最大字段和的动态规划算法
b[j]=max(a[i]+a[i+1]+...+a[j]),1<=i<=j且1<=j<=n,则所求的最大子段和为max(b[j]),1<=j<=n
由b[j]定义知:当b[j-1]>=0时,b[j]=b[j-1]+a[j],
否则,b[j-1]<0,时,b[j]=max(a[i]+a[i+1]+...+a[j])=a[j]
故动态规划为:
b[j]=max(b[j-1]+a[j],a[j]),1<=j<=n
*/    
    public static int getMaxSegmentSumFour(int[] array){ //只需求出最大的b[j],即max(b[j])
        
        int sum=0,b=0;
        for(int i=0;i<array.length;i++){
           if(b>0){
              b+=array[i];
           }else{
               b=array[i];
           }
           if(b>sum){
               sum=b;
           }
           
        }
        return sum;
    }
    public static void main(String[] args) {
        
        int[] array={-2,11,-4,13,-5,-2};
        int maxSegment=getMaxSegmentSumOne(array);
        System.out.println("maxSegmentOne="+maxSegment);
        
        maxSegment=getMaxSegmentSumTwo(array);
        System.out.println("maxSegmentTwo="+maxSegment);
        
        maxSegment=getMaxSegmentSumThree(array,0,array.length-1);
        System.out.println("maxSegmentThree="+maxSegment);
        
        maxSegment=getMaxSegmentSumFour(array);
        System.out.println("getMaxSegmentSumFour="+maxSegment);
        
    }

}

1 0
原创粉丝点击