最大子列和问题

算法复杂度体验

题目:最大子列和问题

给定N个整数序列{A1,A2,…,AN},求函数f(i,j)=max{0,Ai + … +Aj}的最大值

  • 三层循环,暴力破解,算法复杂度O(N^3)
//时间复杂度O(N^3) 
int MaxSequenceSum1(int *a , int cnt)
{
	int ThisSum, MaxSum = 0; 
	int i, j, k;
	for( i = 0; i < N; i++){//确定左起点 
		for( j = i; j < N; j++){//确定右终点 
			ThisSum = 0;
			for( k = i; k <= j; k++){//求i ~ j之间的和 
				ThisSum += a[k];
			}
			if(ThisSum >= MaxSum){//判断,更新结果 
				MaxSum = ThisSum;
			}
		}
	}
	
	return MaxSum; //反回结果 
}
  • 双层循环,暴力破解,算法复杂度O(N^2)
//时间复杂度O(N^2) 
int MaxSequenceSum2(int *a , int cnt){
	int ThisSum, MaxSum = 0;
	int i, j;
	for( i = 0; i < N; i++){//确定左起点 
		ThisSum = 0;
		for( j = i; j < N; j++){//确定右终点 
			ThisSum += a[j];//原基础上加后面一位的值 
			if(ThisSum >= MaxSum){//判断,更新结果 
				MaxSum = ThisSum;
			}
		}
	}
	return MaxSum; //返回结果 
}
  • 分治法,二叉树求解,算法复杂度O(NlogN)
    在这里插入图片描述
//分治 、二叉树 时间复杂度:O(NlogN) 

int max(int a, int b, int c){
	return a > b ? a > c ? a : c : b > c ? b : c;//返回三者最大值 
}

int MaxOpration(int *a, int left, int right){
	int MaxLeftBorderSum = 0, MaxRightBorderSum = 0;//存放跨分界线的结果
	int MaxLeftSum = 0,MaxRightSum = 0;//左右两个子列的结果 
	int LeftSum = 0, RightSum = 0;
	
	if( left == right) return a[left] > 0 ? a[left] : 0;//递归结束条件 
	
	int center = (left + right)/2;//二叉划分 

	MaxLeftSum = MaxOpration( a, left, center); //左子叶结果 
	MaxRightSum = MaxOpration( a, center+1, right);//右子叶结果 
	
	int i;
	//左子叶之和 ,若大于0则赋给MaxLeftBorderSum,若小于0,则 MaxLeftBorderSum不变 
	for( i = center; i >= left; i--){
		LeftSum += a[i];
		if(LeftSum > MaxLeftBorderSum) MaxLeftBorderSum = LeftSum;
	}
	//右子叶之和 ,大于0则赋给MaxRightBorderSum,若小于0,则 MaxRightBorderSum不变  
	for( i = center+1; i <= right; i++){
		RightSum += a[i];
		if(RightSum > MaxRightBorderSum){
			MaxRightBorderSum = RightSum;
		}
	} 
	int MidSum = MaxLeftBorderSum + MaxRightBorderSum;//左右子叶之和 
	return max(MaxLeftSum, MaxRightSum, MidSum);//返回左子叶结果、右子叶结果、边界之和三者最大值 
}

int MaxSequenceSum3(int *a , int cnt){
	//保持不同算法接口一致 
	return MaxOpration( a, 0,cnt - 1 );
} 
  • 在线处理法,算法复杂度O(N)
    “在线”是指每输入一个数据就进行即使处理,在任何一个地方终止,算法都能正确给出当前的解。
int MaxSequenceSum4(int *a , int cnt){
	int i;
	int ThisSum = 0, MaxSum = 0;
	for( i = 0; i < cnt; i++){
		ThisSum += a[i];//累加 
		if(ThisSum > MaxSum) MaxSum = ThisSum;//更新结果 
		else if(ThisSum < 0) ThisSum = 0;//若当前子列结果小于0,表明不会使最大和变大,则舍弃,从当前位置重新开始累加 
	}
	return MaxSum; 
}

四个算法运行时间及其复杂度

  • 完整代码展示
//给定N个整数序列{A1,A2,...,AN},求函数f(i,j)=max{0,Ai + ... +Aj}的最大值 
#include <stdio.h>
#define N 8	//定义长度,可调

//时间复杂度O(N^3) 
int MaxSequenceSum1(int *a , int cnt)
{
	int ThisSum, MaxSum = 0; 
	int i, j, k;
	for( i = 0; i < N; i++){//确定左起点 
		for( j = i; j < N; j++){//确定右终点 
			ThisSum = 0;
			for( k = i; k <= j; k++){//求i ~ j之间的和 
				ThisSum += a[k];
			}
			if(ThisSum >= MaxSum){//判断,更新结果 
				MaxSum = ThisSum;
			}
		}
	}
	
	return MaxSum; //反回结果 
}

//时间复杂度O(N^2) 
int MaxSequenceSum2(int *a , int cnt){
	int ThisSum, MaxSum = 0;
	int i, j;
	for( i = 0; i < N; i++){//确定左起点 
		ThisSum = 0;
		for( j = i; j < N; j++){//确定右终点 
			ThisSum += a[j];//原基础上加后面一位的值 
			if(ThisSum >= MaxSum){//判断,更新结果 
				MaxSum = ThisSum;
			}
		}
	}
	return MaxSum; //返回结果 
}

//分治 、二叉树 时间复杂度:O(NlogN) 

int max(int a, int b, int c){
	return a > b ? a > c ? a : c : b > c ? b : c;//返回三者最大值 
}

int MaxOpration(int *a, int left, int right){
	int MaxLeftBorderSum = 0, MaxRightBorderSum = 0;//存放跨分界线的结果
	int MaxLeftSum = 0,MaxRightSum = 0;//左右两个子列的结果 
	int LeftSum = 0, RightSum = 0;
	
	if( left == right) return a[left] > 0 ? a[left] : 0;//递归结束条件 
	
	int center = (left + right)/2;//二叉划分 

	MaxLeftSum = MaxOpration( a, left, center); //左子叶结果 
	MaxRightSum = MaxOpration( a, center+1, right);//右子叶结果 
	
	int i;
	//左子叶之和 ,若大于0则赋给MaxLeftBorderSum,若小于0,则 MaxLeftBorderSum不变 
	for( i = center; i >= left; i--){
		LeftSum += a[i];
		if(LeftSum > MaxLeftBorderSum) MaxLeftBorderSum = LeftSum;
	}
	//右子叶之和 ,大于0则赋给MaxRightBorderSum,若小于0,则 MaxRightBorderSum不变  
	for( i = center+1; i <= right; i++){
		RightSum += a[i];
		if(RightSum > MaxRightBorderSum){
			MaxRightBorderSum = RightSum;
		}
	} 
	int MidSum = MaxLeftBorderSum + MaxRightBorderSum;//左右子叶之和 
	return max(MaxLeftSum, MaxRightSum, MidSum);//返回左子叶结果、右子叶结果、边界之和三者最大值 
}

int MaxSequenceSum3(int *a , int cnt){
	//保持不同算法接口一致 
	return MaxOpration( a, 0,cnt - 1 );
} 

int MaxSequenceSum4(int *a , int cnt){
	int i;
	int ThisSum = 0, MaxSum = 0;
	for( i = 0; i < cnt; i++){
		ThisSum += a[i];//累加 
		if(ThisSum > MaxSum) MaxSum = ThisSum;//更新结果 
		else if(ThisSum < 0) ThisSum = 0;//若当前子列结果小于0,表明不会使最大和变大,则舍弃,从当前位置重新开始累加 
	}
	return MaxSum; 
}

int main()
{
	int a[N] = {1,2,-1,2,-3,1,-1,2};
	int sum1 = MaxSequenceSum1(a, N);
	int sum2 = MaxSequenceSum2(a, N);
	int sum3 = MaxSequenceSum3(a, N);
	int sum4 = MaxSequenceSum4(a, N);
	
	printf("测试一结果:%d\n测试二结果:%d\n测试三结果:%d\n测试结果四:%d", sum1, sum2, sum3,sum4);

	return 0;
} 


评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值