最大子段和

题目

最大子段和

给出一个长度为 n 的序列 a,选出其中连续且非空的一段使得这段和最大

方法一 暴力枚举每一子串

直接枚举起点终点取最大子段

时间复杂度:O(n^3)

int MaxSubSequenceSum(int a[],int Left,int Right){
	
	int thissum;
	int res = 0;
	int i;
	int j;
	int k;
	
	
	for(i = Left; i <=Right; ++i){
		for(j = i;j <= Right; ++j){
			
			thissum = 0;
			for(k = i;k <= j;++k)
				thissum += a[k];
			
			res = res > thissum ? res : thissum;
			
		}
	}
	
	
	return res; 
}

方法二 优化暴力枚举

方法一第三层循环可以直接累加进thissum

不用每个都来一遍

时间复杂度:O(n2)

int MaxSubSequenceSum(int a[],int Left,int Right){
	
	int thissum;
	int res = 0;
	int i;
	int j;
	
	
	
	for(i = Left; i <=Right; ++i){
		
		thissum = 0;		
		for(j = i;j <= Right; ++j){
		
			thissum += a[j]; 
			res = res > thissum ? res : thissum;
		}
	}
	
	
	return res; 
}

方法三 分治

将串分为两部分 [l, mid] 与 [mid +1, r]

最大和子段 [i, j]必处于三种情况之一

  1. l=<i <=j<=mid
    
  2. l=<i <=mid<=j
    
  3. mid + 1<=i <= j
    

左半边最大字段和

或者

右半边最大子段和

或者

跨越左右的最大子段和

int MaxSubSequenceSum(int a[],int Left,int Right){
	
	
	int ans = 0;
	if(Left  == Right)
		return a[Left] ;
		
	int mid = (Left + Right)>>1;
	
	int ans1 = 0;
	int ans2 = 0;
	int thissum = 0;
	int i = 0;
	//实现跨越左右的关键
	for(i = mid;i >= Left;--i){
		thissum += a[i];
		if(thissum > ans1)	ans1 = thissum;
	}
	//同理
	thissum = 0;
	for(i = mid + 1;i <= Right; ++i){
		thissum += a[i];
		if(thissum > ans2)	ans2 = thissum;
	}
	
	return max(max(MaxSubSequenceSum(a, Left,mid), MaxSubSequenceSum(a, mid + 1,Right)), ans1 + ans2);
}

方法四 动态规划

其实在暴力的优化的时候就已经用过了

就是利用之前的信息进行更新

而不是每次进行重复累加


int MaxSubSequenceSum(int a[],int Left,int Right){
	
	int ans = 0;
	int thissum = 0;
	
	
	for(int i = Left;i < Right + 1; ++i ){
	    
	    thissum += a[i];
	    if(thissum < 0){
	        thissum = 0;//之前子段贡献为负数可以舍弃了
	    }
	    else if(thissum > ans){
	        ans = thissum;//取最大值
	    }
	    
	}
    return ans;	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值