1. 程式人生 > >求最大子序列和(Java實現)

求最大子序列和(Java實現)

【問題描述】最大子序列和問題:給定整數A1, A2, ..., An(可能有負數),ΣAk的最大值(為方便起見,如果所有整數均為負數,則最大子序列和為0)。

通過四種方式來完成演算法的實現,時間複雜度分別為:O(N*N*N)、O(N*N)、O(N*log N)、O(N)

【原始碼1】

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");
	}
}
【原始碼2】
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】

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");
	}
	
}
【原始碼4】
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");
	}
}