1. 程式人生 > >最大子序列和問題求解

最大子序列和問題求解

問題: 給定(可能有負數)的整數 A1,A2,,AnA_{1},A_{2},\ldots ,A_{n} 的最大值。 解決此問題有四個演算法: 演算法一:

public static int maxSubSuml ( int [ ] a ) {
   int maxSum = 0 ;
   
   for ( int i = 0 ; i < a.length ; i ++) {
   	for ( int j = i ; j < a.length ; j++ ) {

   		int thisSum = 0 ;

   		for ( int k = i ;
k <= j ; k ++) { thisSum += a [ k ] ; } if ( thisSum > maxSum ) { maxSum = thisSum ; } } } return maxSum ; }

執行時間為 O(N3)O\left( N^{3}\right) ,這取決於第9、10行,按照(粗略的計算)最壞的要求計算運行了3賜迴圈。 按照精確的計算為:i=0N1j=iN1k=ij1\sum ^{N-1}_{i=0}\sum ^{N-1}_{j=i}\sum ^{j}_{k=i}1

得到 N3+3N2+2N6\dfrac {N^{3}+3N^{2}+2N}{6}。可以看出在第三層for迴圈中過分的耗費了時間。 演算法二:

public static int maxSubSum2( int [ ] a ) {
   int maxSum = 0 ;
   
   for ( int i = 0 ; i < a.length ; i++ ) {
   	int thisSum = 0 ;
   	for ( int j = i ; j < a.length ; j++ ) {
   		thisSum +=
a [ j ] ; if ( thisSum > maxSum ) { maxSum = thisSum ; } } } return maxSum ; }

運算時間為(大概): O(N2)O\left( N^{2}\right) 演算法三: “分治”策略:將問題分成兩個大致相等的子問題,然後遞迴的對它們求解;然後再將兩個子問題的解修補到一起並按照要求做一些附加工作,最後得到整個問題的解。

public static int maxSumRec ( 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 maxLeftSun = maxSumRec ( a, left, center ) ;
	int maxRightSum = maxSumRec ( a, center + 1 , right );
	
	int maxLeftBorderSum = 0 ;
	int leftBorderSum = 0 ;
	
	for (int i=center;i>=left;i--){
		leftBorderSum+=a[i];
		if(leftBorderSum>maxLefBorderSum){
			maxLeftBorderSum=leftBorderSum;
		}
	}
	
	int maxRightBorderSum=0;
	int rightBorderSum=0;
	for(int i=center+1;i<=right;i++){
		rightBorderSum+=a[i];
		if(rightBorderSum>maxRightBorderSum){
			maxRightBorderSum=rightBorderSum;
		}
	}
	
	//max(a,b,c);是求a,b,c,三者中的最大值
	return max(maxLeftSum,maxRightSum,maxLeftBorderSum+maxRightBorderSum);
	
}

運算時間為 O(NlogN)O\left( N\log N\right) ,這個演算法分析N是偶數。 演算法四:

public static int maxSubSum(int [ ] a ){
	int maxSum=0;
	int thisSum=0;
	
	for(int j=0; j<a.length; j++){
		thisSum+=a[j];
		if(thisSum>maxSum){
			maxSum=thisSum;
		}
		else if(thisSum<0){
			thisSum=0;
		}
		
		return maxSum;
	}
}

執行時間為:O(N)O\left( N\right)

分析

演算法1和演算法2中,j代表當前序列的終點,而i代表當前序列的起點。而如果我們不需要知道最佳子序列的具體位置的話,i的使用則可以被優化(演算法四)。 演算法四:假設a[i]是負的,那麼它不是最有序列的起點,因為都可以通過a[i+1]作為起點來改進。同樣,任何負的子序列都不是最優序列的字首。i不僅可以推到i+1,還可以推到j+1;因此我們的最優解一個也不會錯過。

聯機演算法

在任意時刻演算法對要操作的資料只讀入(掃描)一次,一旦被讀入並處理,它就不需要在被記憶了,而在此處理過程中演算法能對它已經讀入的資料立即給出相應子序列問題的正確答案。 優點: 佔用空間少,所用時間少。 缺點: 不宜設計,正確性不易觀察,同時附加保留資訊較少。