求最大子序列和(Java實現)
阿新 • • 發佈:2019-01-30
【問題描述】最大子序列和問題:給定整數A1, A2, ..., An(可能有負數),ΣAk的最大值(為方便起見,如果所有整數均為負數,則最大子序列和為0)。
通過四種方式來完成演算法的實現,時間複雜度分別為:O(N*N*N)、O(N*N)、O(N*log N)、O(N)
【原始碼1】
【原始碼2】package cn.edu.nwsuaf.cie.qhs.maxsubsum; /** * 求最大子序列和(1) * @author 靜寞小森(滄海森林) * 下面的這種做法來求和,應該是程式設計師最直觀想到的,時間複雜度為:O(N*N*N) * */ public class MaxSubSum1 { public static int maxSum(int[] array){ int maxSum = 0; for(int i = 0 ; i < array.length ; i++){ for(int j = i ; j < array.length;j++){ int curSum = 0; for (int k = i; k <= j; k++){ curSum += array[k]; if(curSum > maxSum){ maxSum = curSum; } } } } return maxSum; } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int[] array = new int[]{4,-3,5,-2,-1,2,6,-2}; long startTime = System.nanoTime(); System.out.println("最大子序列和為:"+MaxSubSum1.maxSum(array)); long endTime = System.nanoTime(); System.out.println("程式耗時為:"+(endTime-startTime)+" ns"); } }
package cn.edu.nwsuaf.cie.qhs.maxsubsum; /** * 求最大子序列和(2) * * @author 靜寞小森(滄海森林) * 第二種做法,是對做法(1)進行一下分析,可以得知,程式中第三層迴圈不是必須的,因為這個過程可以包含在第二層迴圈中,所以可以考慮去掉。 * 去掉一個for迴圈,可以得到迴圈的次數減少了n的倍數,所以時間複雜度為O(N*N) * */ public class MaxSubSum2 { public static int maxSum(int[] array) { int maxSum = 0; for (int i = 0; i < array.length; i++) { int curSum = 0;//這個變數的宣告和初始化要提到第二層for的外面 for (int j = i; j < array.length; j++) { //在這裡,就已經包括了(1)中的k的那個迴圈 curSum += array[j]; if (curSum > maxSum) { maxSum = curSum; } } } return maxSum; } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int[] array = new int[]{4,-3,5,-2,-1,2,6,-2}; long startTime = System.nanoTime(); System.out.println("最大子序列和為:"+MaxSubSum2.maxSum(array)); long endTime = System.nanoTime(); System.out.println("程式耗時為:"+(endTime-startTime)+" ns"); } }
【原始碼3】
【原始碼4】package cn.edu.nwsuaf.cie.qhs.maxsubsum; /** * 求最大子序列和(3) * * @author 靜寞小森(滄海森林) * 第三種方法,我們將採用“分而治之”的想法,進行編碼。因為本程式,最大子序列和只能出現在三個位置上: * 左半部分、右半部分、跨著左右兩半部分;所以我們可以採用二分的“分而治之”來進行分開解決問題。可知其時間複雜度為:O(N*log N) */ public class MaxSubSum3 { private static int max3(int a,int b,int c){ int temp = Math.max(a, b); return Math.max(temp, c); } private static int maxSumRec(int[] array,int left,int right){ if (left == right) return array[left] > 0 ? array[left] : 0; //二分 int center = (left+right)>>1;//右移位一次,為除法的除以2,但是效率比較高 int maxLeftSum = maxSumRec(array,left,center); int maxRightSum = maxSumRec(array,center+1,right); int maxLeftBorderSum = 0, curLeftBorderSum = 0; for(int i = center;i >= left; i--){ curLeftBorderSum += array[i] ; if(curLeftBorderSum > maxLeftBorderSum) maxLeftBorderSum = curLeftBorderSum; } int maxRightBorderSum = 0, curRightBorderSum = 0; for(int i = center+1; i <= right;i++){ curRightBorderSum += array[i]; if(curRightBorderSum > maxRightBorderSum) maxRightBorderSum = curRightBorderSum; } return max3(maxLeftSum,maxRightSum,maxRightBorderSum+maxLeftBorderSum); } public static int maxSum(int[] array){ return maxSumRec(array,0,array.length-1); } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int[] array = new int[]{4,-3,5,-2,-1,2,6,-2}; long startTime = System.nanoTime(); System.out.println("最大子序列和為:"+MaxSubSum3.maxSum(array)); long endTime = System.nanoTime(); System.out.println("程式耗時為:"+(endTime-startTime)+" ns"); } }
package cn.edu.nwsuaf.cie.qhs.maxsubsum;
/**
* 求最大子序列和(4)
*
* @author 靜寞小森(滄海森林)
* 第四種方法,是通過一個“聯機演算法”進行的最優演算法計算,時間複雜度僅為O(N)
*
*/
public class MaxSubSum4 {
public static int maxSum(int[] array){
int maxSum = 0, curSum = 0;
for (int i = 0; i < array.length; i++){
curSum += array[i];
if(curSum > maxSum){
maxSum = curSum;
}else if(curSum < 0){
curSum = 0;
}
}
return maxSum;
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] array = new int[]{4,-3,5,-2,-1,2,6,-2};
long startTime = System.nanoTime();
System.out.println("最大子序列和為:"+MaxSubSum3.maxSum(array));
long endTime = System.nanoTime();
System.out.println("程式耗時為:"+(endTime-startTime)+" ns");
}
}