数组的连续最大子段和

最大子段和问题描述

给定由 n 个整数(可能为负整数)组成的序列a1,a2,a3...an,求该数列中连续子段和最大!

    例如:当(a1,a2,a3,a4,a5)=(-2,11,-4,13,-5,-2)时,最大字段和为 20 (11 + (-4) + 13);

       以下例子都是以int data[6] = {-2,11,-4,13,-5,-2};    int n = 6;

算法一:对所有满足0<=i<=j<=n的(i,j)整数对进行迭代,对每个整数对,程序都要计算array[i...j]的总和,并检验该总和是否大于迄今为止的最大总和

这段代码简洁明了,便于理解,但是程序执行的速度很慢,时间复杂度为O(n^3)

int solveMaxCSSum1(){
	int maxSum = 0;				//记录最大子段和的变量 
	int tempSum;				//记录最大子段和的临时变量 
	int i,j,k;
	for(i=0;i<n;i++){
		for(j=i;j<n;j++){
			tempSum = 0;		//每次从 i 加到 j 时,临时变量都必须归零 
			for(k=i;k<=j;k++){	//从第 i 个数依次累加到第 j 个数 
				tempSum += data[k];
				if(maxSum < tempSum){
					maxSum = tempSum;
				} 
			}
		} 
	}	
	return maxSum;
} 


算法二:对于算法一有一个明显的缺点,大量的计算重复。大家可以注意到:

这段代码简洁明了,便于理解,相比算法一程序执行的速度较快,时间复杂度为O(n^2)

array[i...j]的总和与前面计算出的总和(array[i...j-1])密切相关

只需要在其基础上累加即可,无需大量重复计算!

int solveMaxCSSum2(){
	int maxSum = 0;				//记录最大子段和的变量 
	int tempSum;				//记录最大子段和的临时变量 
	int i,j,k;
	for(i=0;i<n;i++){
		tempSum = 0;			//每次 i 从一个新位置开始,临时变量都必须归零
		for(j=i;j<n;j++){
			tempSum += data[j]; //在之前的基础上直接进行累加 
			if(maxSum < tempSum){
					maxSum = tempSum;
			} 
		} 
	}	
	return maxSum;
} 

算法三:可以采用分治算法求解,采用二分法进行二分,然后进行递归求解,分别求出左边连续子段和最大值,右边连续子段和最大值,

以及左边和右边连续子段和最大值之和,三者进行比较,从中选择一个最大值进行返回!(这个值即就是当前划分的小区间中最大值)

这段代码不太便于理解,但是程序相对于算法二执行的速度快,时间复杂度为O(n*logn)

int solveMaxCSSum3(int left,int right){
    int maxSum = 0;  
    if(left == right)   //如果序列长度为 1,直接求解  
    {  
        if(data[left] > 0){
        	maxSum = data[left];
        }else{
        	maxSum = 0;  
        } 
    }else{  
        int center = (left + right) / 2;   //二分法划分  
        int leftMaxSum = solveMaxCSSum3(left,center);    	//递归求解左半部分最大值 
        int rightMaxSum = solveMaxCSSum3(center + 1, right);//递归求解右半部分最大值 
        int leftMax = 0;		//记录左边最大值  
        int leftMaxTemp = 0;  	//记录左边最大值的临时变量 
        for(int i = center; i >= left; i--)  
        {  
            leftMaxTemp += data[i];  
            if(leftMaxTemp > leftMax){ 
				leftMax = leftMaxTemp;   //左边最大值放在 leftMax
			}  
        }  
        int rightMax = 0;   
        int rightMaxTemp = 0;  
        for(int j = center + 1; j <= right; j++)  
        {  
            rightMaxTemp += data[j];  
            if(rightMaxTemp > rightMax){
            	rightMax = rightMaxTemp;  //右边最大值放在 rightMax
            } 
        }  
        maxSum = leftMax + rightMax;//(左边最大值和右边最大值之和)计算第 3 种情况的最大子段和  
        //比较(左边最大值)和(右边最大值)以及(两边最大值之和)进行比较,从中选择一个最大值返回 
        if(maxSum < leftMaxSum){
			maxSum = leftMaxSum; 
		} 
        if(maxSum < rightMaxSum){
			maxSum = rightMaxSum; 
		} 
    }  
    return maxSum;  
}

算法四:使用动态规划来求解 ,data[]数组我们易知,当maxSumTemp > 0时,maxSumTemp = data[i] + maxSumTemp (越加越大),否则maxSumTemp = data[i](不然越加越小

这段代码便于理解,但是程序相对于算法三执行的速度最快,时间复杂度为O(n)

int solveMaxCSSum4(){
	int maxSum = 0;
	int maxSumTemp = 0;
	maxSum = maxSumTemp = data[0];	//初始化 
	for(int i=1;i<n;i++){
		if(maxSumTemp > 0 ){	//最大值临时变量只有大于零,才可能越加越大 
			maxSumTemp += data[i];
		}else{			// 最大值临时变量只有小于零,直接等于data[i],否则越加越小 
			maxSumTemp = data[i];
		}
		if(maxSumTemp > maxSum){	//判断赋值 
			maxSum = maxSumTemp;
		}
	}
	return maxSum;
} 








  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值