最大的子序列和問題

http://blog.csdn.net/zhutulang/article/details/7505785

參考:數據結構與算法分析——Java語言描述

(美) Mark Allen Weiss

給定整數 A1,A2,……AN  (可能有負數),求這個整數序列的最大子序列和。(原書假定如果所有整數爲負數,則最大的子序列的和爲0。我們這裏去掉了這個假定,算法1和算法2只需要把maxSum初始設爲 a[0] 即可,算法3做了些修改)

例如:-2 ,11,-4,13,-5,-2, 答案爲 20(從A2--A4)

算法1 :

算法1是一種比較容易想到的方法。我們可以這樣想,這個子序列可能從第1個元素開始,也有可能從第2、第3、……個元素開始。我們初始假設最大的子序列和 maxSum 是第一個元素。然後分別從第1、第2、………個元素開始計算子序列和,並和當前的和 maxSum 比較,如果大於 maxSum,就將此子序列和賦值給maxSum。

代碼如下:

[java] view plaincopy

  1. //算法1
  2. public int maxSubSum1(int []a){  
  3. int thisSum=0,maxSum=a[0];  
  4. for(int i=0;i<a.length;i++)  
  5.         {  
  6.             thisSum=0;  
  7. for(int j=i;j<a.length;j++)  
  8.             {  
  9.                 thisSum+=a[j];  
  10. if(thisSum>maxSum){  
  11.                     maxSum=thisSum;  
  12.                 }  
  13.             }  
  14.         }  
  15. return maxSum;  
  16.     }  

 算法2:

 如圖:

我們可以把這個整數數列分成前後兩部分。那麼最大的子序列和可能出現在三處:前半部分某子序列(設其和爲maxLeft),後半部分某子序列(設其和爲maxRight),中間部分某子序列(設其和爲maxCenter)。前兩種情況可以通過遞歸求解。第三種情況,我們通過分析可知,這種情況下的最大和可以通過求出前半部分的最大和(包含前半部分的最後一個元素)以及後半部分的最大和(包含後半部分的第一個元素)而得到。

代碼如下:

[java] view plaincopy

  1. //算法2
  2. public int maxSubSum2(int []a,int left,int right){  
  3. int maxSum=a[0];  
  4. if(left==right){  
  5. if(a[left]>maxSum)  
  6.                 maxSum=a[left];  
  7.           }else{  
  8. int center=(left+right)/2;  
  9. //左半部分最大子序列和
  10. int maxLeft=maxSubSum2(a,left, center);  
  11. //右半部分最大子序列和
  12. int maxRight=maxSubSum2(a, center+1, right);  
  13. //求左半部分包含最後一個元素的最大和
  14. int maxLeftBorder=a[center],leftBorderSum=0;  
  15. for(int i=center;i>=left;i--){  
  16.                   leftBorderSum+=a[i];  
  17. if(leftBorderSum>maxLeftBorder){  
  18.                       maxLeftBorder=leftBorderSum;  
  19.                   }  
  20.               }  
  21. //求右半部分包含第一個元素的最大和
  22. int maxRightBorder=a[center+1],rightBorderSum=0;  
  23. for(int j=center+1;j<=right;j++){  
  24.                   rightBorderSum+=a[j];  
  25. if(rightBorderSum>maxRightBorder){  
  26.                       maxRightBorder=rightBorderSum;  
  27.                   }  
  28.               }  
  29. //橫跨前後兩部分的最大子序列和
  30. int maxCenter=maxLeftBorder+maxRightBorder;  
  31.               maxSum=Math.max(maxCenter,Math.max(maxLeft, maxRight));  
  32.           }  
  33. return maxSum;  
  34.     }  

算法3:

這種算法效率最高。thisSum每加一個元素後,判斷它是否大於 maxSum ,如果大於則 maxSum=thisSum 。判斷 thisSum是否小於0,如果小於0,那麼說明計算到當前這個位置上的子序列的和是個負數。thisSum=0的效果就相當於把子序列的起始位置推進到當前這個子序列的最後一個位置+1,開始一個新的子序列了。

代碼如下:

[java] view plaincopy

  1. //算法3
  2. public int maxSubSum3(int []a){  
  3. int maxSum=a[0],thisSum=0;  
  4. for(int i=0;i<a.length;i++){  
  5.             thisSum+=a[i];  
  6. if(thisSum>maxSum){  
  7.                 maxSum=thisSum;   
  8.             }  
  9. if(thisSum<0){  
  10.                 thisSum=0;  
  11.             }     
  12.         }  
  13. return maxSum;  
  14.     }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章