最大子序列和问题求解

问题: 给定(可能有负数)的整数 A 1 , A 2 , … , A n A_{1},A_{2},\ldots ,A_{n} A1,A2,,An 的最大值。
解决此问题有四个算法:
算法一:

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 ( N 3 ) O\left( N^{3}\right) O(N3) ,这取决于第9、10行,按照(粗略的计算)最坏的要求计算运行了3赐循环。
按照精确的计算为: ∑ i = 0 N − 1 ∑ j = i N − 1 ∑ k = i j 1 \sum ^{N-1}_{i=0}\sum ^{N-1}_{j=i}\sum ^{j}_{k=i}1 i=0N1j=iN1k=ij1 得到 N 3 + 3 N 2 + 2 N 6 \dfrac {N^{3}+3N^{2}+2N}{6} 6N3+3N2+2N。可以看出在第三层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 ( N 2 ) O\left( N^{2}\right) O(N2)
算法三:
“分治”策略:将问题分成两个大致相等的子问题,然后递归的对它们求解;然后再将两个子问题的解修补到一起并按照要求做一些附加工作,最后得到整个问题的解。

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 ( N log ⁡ N ) O\left( N\log N\right) O(NlogN) ,这个算法分析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) O(N)

分析

算法1和算法2中,j代表当前序列的终点,而i代表当前序列的起点。而如果我们不需要知道最佳子序列的具体位置的话,i的使用则可以被优化(算法四)。
算法四:假设a[i]是负的,那么它不是最有序列的起点,因为都可以通过a[i+1]作为起点来改进。同样,任何负的子序列都不是最优序列的前缀。i不仅可以推到i+1,还可以推到j+1;因此我们的最优解一个也不会错过。

联机算法

在任意时刻算法对要操作的数据只读入(扫描)一次,一旦被读入并处理,它就不需要在被记忆了,而在此处理过程中算法能对它已经读入的数据立即给出相应子序列问题的正确答案。
优点: 占用空间少,所用时间少。
缺点: 不宜设计,正确性不易观察,同时附加保留信息较少。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值