求输入序列的最大子序列

问题:给出一个有限长度的实数序列,求出其子序列中和为最大的子序列值?

方法1:设置两个循环遍历序列,分别作为子序列的左右两端,再加一个循环将子序列中所有项相加,最后算法的时间复杂度为O(N^{3})

void maxSubList(int list[],int length) {
	int maxSublist = 0,l=0,r=0;
	int thisSubList = 0;
	int i ,j,k;
	for (i = 0; i < length; i++) {		//定义序列左端
		
		for (j = i; j < length; j++) {	//定义序列右端
			for (k = i; k < j; k++) {
				thisSubList += list[j];		//将序列从左端i加到右端j
			}
			
			if (thisSubList > maxSublist)
			{
				maxSublist = thisSubList;		//更新最大序列
				l = i;							//记录最大子序列的左右下标
				r = j;
			}
		}
	}
	cout << maxSublist << endl;
	cout << l<<","<<r << endl;
}

方法2:首先思考,算法需要做的是遍历所有的子序列,在遍历过程中就可以将所有的子序列进行求和比较,然后更新最大子序列即可,所以第三个循环可以省去。最后算法的时间复杂度为O(N^{2})

void maxSubList(int list[],int length) {
	int maxSublist = 0,l=0,r=0;
	int thisSubList = 0;
	int i ,j;
	for (i = 0; i < length; i++) {		//定义序列左端
		thisSubList = 0;
		for (j = i; j < length; j++) {	//定义序列右端
		
				thisSubList += list[j];		//将序列从左端i加到右端j
			
			if (thisSubList > maxSublist)
			{
				maxSublist = thisSubList;		//更新最大序列
				l = i;							//记录最大子序列的左右下标
				r = j;
			}
		}
	}
	cout << maxSublist << endl;
	cout << l<<","<<r << endl;
}

方法3:根据分治的思想,对序列进行划分。最大子序列可以在左边子式,可以在右边子式,也可以是跨越中间的子式,然后将左右子式依次划分,求子式中的最大子式。如图所示:

int MaxSubList(int numL, int numR,int* list) {
	if (numL == numR) {

		return list[numL];				//定义最终的返回值
	}
	int l = 0, r = 0;
	int numMid = (numL+numR)/2;
	int lMax = MaxSubList(numL, numMid, list);//回调求左边的最大子式
	int rMax = MaxSubList(numMid + 1, numR, list);//回调求右边的最大子式
	int midMax=0,sumL=list[numMid],sumR=list[numMid+1],sum=0;  
	for (int i = numMid; i >=numL; i--) {
		sum += list[i];									
		if (sum > sumL)										//计算中间部分的最大子式
			sumL = sum;
	}								
	sum = 0;
	for (int j = numMid + 1; j <= numR; j++) {
		sum += list[j];
		if (sum > sumR)
			sumR = sum;
	}

	midMax = sumL + sumR;
	if (lMax > midMax)
	{
		midMax = lMax;								//判断最后的大小

	}
	if (rMax > midMax)
	{
		midMax = rMax;

	}


	return  midMax; 
}

最后算法的时间复杂度为O(NlogN)

4、最后介绍一下在线处理算法。在线处理的意思就是边读入数据边进行判断整理,在逐项累加的过程中判断累加数列是否为负,若为负数,则加后面的项只会使后面的数变小,所以清空累加数列。然后判断累加后的数列与之前记录的最大数列之间的大小,最后得出结果。它的算法复杂度为O\left ( N\right )

int MaxSubList(int* list,int length) {
	int thisSum = 0, maxSum = 0,startNum=0,stopNum=0;
	for (int i = 0; i < length; i++) {
		thisSum += list[i];					//逐项累加
		if (thisSum < 0) {
			thisSum = 0;					//判断累加后的数列若为负数,则舍弃该累加数列
			startNum = i + 1;				//同时将子数列起始序号重置
		}
		if (thisSum > maxSum) {
			maxSum = thisSum;				//判断累加后的数列若大于之前记录的最大子数列,则对最大子数列进行更新
			stopNum = i;					//同时将子数列的终止序号重置
		}
	}
	cout << startNum << "," << stopNum << endl;
	return maxSum;

该算法不仅时间复杂度最低,而且还能同时求出最大子数列的起始,是目前最优的算法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值