最大子序列和問題的四種求解以及他們的時間複雜度

最大子序列求和的問題就是對於給定的整數數列(裏面可能有負數)A1,A2,…AN,求Ai到Ak的和的最大值。
例如 -2,11,-4,13,-5,-2 這個數列的最大子序列和就是11-4+13=20。下面用四種方法實現這個功能。時間複雜度依次減小。

  1. 用三個for循環


public class MaxSubSum {

   public static void main(String[] args) {

     int a[]={-2,11,-4,13,-5,-2};

     int maxsum=0,i,j,k;

     for(i=0;i<a.length;i++){

        for(j=i;j<a.length;j++){

          int thissum=0;

          for(k=i;k<=j;k++){

             thissum=thissum+a[k];

             if(thissum>maxsum){

               maxsum=thissum;

             }

          }

        }

     }

     System.out.println(maxsum);

   }

}


很顯然這個的時間複雜度是O(N3

  1. 用兩個for循環,上面的第三個for是可以不用的


public class MaxSubSum2 {

   public static void main(String[] args) {

     int a[]={-2,11,-4,13,-5,-2};

     int maxsum=0,i,j;

     for(i=0;i<a.length;i++){

        int thissum=0;

        for(j=i;j<a.length;j++){

          thissum=thissum+a[j];

          if(thissum>maxsum){

             maxsum=thissum;

          }
       }

     }

     System.out.println(maxsum);
}

}

 


少了一個for,時間複雜度爲O(N2

  1. 用遞歸,程序較多一點


public class MaxSubSum3 {

   public int maxsum(int a[],int left,int right){

     if(left==right){                  //基準情況

        if(a[left]>0){

          return a[left];

        }

        else

        {

          return 0;

        }

     }

     int center=(left+right)/2;

     int maxleftsum=maxsum(a,left,center);      //左邊遞歸

     int maxrightsum=maxsum(a,center+1,right);   //右邊遞歸

     int maxleftbodersum=0,leftbodersum=0;

     for(int i=center;i>=left;i--){

        leftbodersum=leftbodersum+a[i];

        if(leftbodersum>maxleftbodersum){

          maxleftbodersum=leftbodersum;

        }

     }

     int maxrightbodersum=0,rightbodersum=0;

     for(int i=center+1;i<=right;i++){

        rightbodersum=rightbodersum+a[i];

        if(rightbodersum>maxrightbodersum){

          maxrightbodersum=rightbodersum;

        }

     }

     return max(maxleftsum,maxrightsum,maxleftbodersum+maxrightbodersum);

   }

   private int max(int x, int y, int z) {

     int temp,result;

     if(x>y){

        temp=x;

     }

     else{

        temp=y;

     }

     if(temp>z){

        result=temp;

     }

     else{

        result=z;

     }

     

     return result;

   }

 

   /**

    * @param args

    */

   public static void main(String[] args) {

     int a[]={-2,11,-4,13,-5,-2};

     MaxSubSum3 max=new MaxSubSum3();

     max.maxsum(a, 0, a.length-1);

     System.out.println(max.maxsum(a, 0, a.length-1));

 

   }

 

}


這兩個for是找出含有中間項的和的最大值。這個算法遞歸的是每次變成N/2,然後for循環的時間複雜度爲O(N),整個算法的時間複雜度是O(NlogN)。

  1. 最後一個也是最優的算法了吧 ,因爲不需要知道這個子序列在哪裏,只需要知道最後的值,子序列中第一項如果是負數那麼肯定不能是最大的了。


public class MaxSubSum4
{

   public static void main(String[] args) {

     int a[]={-2,11,-4,13,-5,-2};

     int maxsum=0,thissum=0;

     for(int i=0;i<a.length;i++){

        thissum=thissum+a[i];

        if(thissum>maxsum){

          maxsum=thissum;

        }

        else if(thissum<0){

          thissum=0;

        }

     }

     System.out.println(maxsum);
  
   }

}

這個只有一個for循環,所以時間複雜度爲O(N)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章