最大子列和

文章介绍了两种方法来寻找一个整数序列的最大子列和。方法一是使用分治法,将序列分成左右两部分,递归求解并结合边界扫描找到最大子列和,时间复杂度为O(nlogn)。方法二是在线处理,每次新输入一个数据就更新最大和,遇到负数则重置,这种方法的时间复杂度为O(n),效率更高。
摘要由CSDN通过智能技术生成

   问题描述给定n个整数的序列 a,a…,a. ,求序列的最大子列和 fo在这里,“子列”被定义为原始序列中连续的一段数字,我们要找的是具有最大和的一段连续的子列,并且返回它的和。如果这个最大和是负数,那么取0为最终答案。例如给定序列{-2,11,-4,13,-5,-2},其最大子列为 {11,-4,13},和为20。

方法一:分治法

第一步:将序列从中分为左、右两个序列;

第二步:递归求得两子列的最大和S左和S右;

第三步:从中分点分别向左右两边扫描,找出跨过分界线的最大子列和S中;

第四步:Smax=Max{S左,S中,S右};

//方法一:分治法
int DivideandConquer(int list[],int left,int right)
{
	int MaxLeftSum, MaxRightSum;//存放左右子问题的解
	int MaxLeftBorderSum, MaxRightBorderSum;//存放跨分界线的结果
	int LeftBorderSum, RightBorderSum;//存放左右边的结果
	int center, i;

	if (left ==right )//递归终止条件,子列只剩一个元素
	{
		if (list[left] > 0) return list[left];
		else return 0;
	}
	/*下边是"分"的过程*/
	center = (right + left) / 2;//找到中分点
	/*递归求左右子列的最大和*/
	MaxLeftSum = DivideandConquer(list, left, center);
	MaxRightSum = DivideandConquer(list, center + 1, right);

	/*下面求跨分界线的最大子列和*/
	MaxLeftBorderSum = 0;LeftBorderSum = 0;
	for (i = center; i >= left; i--)/*从中线向左扫描*/
	{
		LeftBorderSum = LeftBorderSum + list[i];
		if (LeftBorderSum > MaxLeftBorderSum)
			MaxLeftBorderSum = LeftBorderSum;
	}//左边扫描结束
	MaxRightBorderSum = 0; RightBorderSum = 0;
	for (i = center + 1; i < right; i++)/*从中线向右扫描*/
	{
		RightBorderSum = RightBorderSum + list[i];
		if (RightBorderSum > MaxRightBorderSum)
			MaxRightBorderSum = RightBorderSum;
	}//右边扫描结束

	/*下边返回治的结果*/
	return Max(MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum);
}

int MaxSubseqSum1(int list[], int n)
{
	/*尽量使接口相同*/
	return DivideandConquer(list, 0, n - 1);
}

时间复杂度:O(nlogn)

分治法的过程可能不太好理解,基本思想也就是将一个大问题转化成相同的小规模问题,每个过程的数组如下图:

 方法二:在线处理

        “在线”意思是指每输入一个数据就进行即时的处理,得到的结果相当于对前面已经读入的数据都成立的解。无需存储输入序列就能得到任何时刻的最大的子列和。

下面算法的核心是基于下面的一个事实:

如果整数序列{a1,a2,....,an}的最大和子列是{ai,....aj},对最大和子列中的任意序列和都大于等于0.

也很好理解,就是 如果序列和出现负的,那就相当于序列和减小,就需要将负的那个序列剔除。

//在线处理
int MaxSubsequSum2(int list[], int n)
{
	int ThisSum = 0, MaxSum = 0;
	int i = 0;
	for (i = 0; i < n; i++)
	{
		ThisSum = ThisSum + list[i];//向右累加
		if (ThisSum > MaxSum)
			MaxSum = ThisSum;/*更新最大值*/
		else if (ThisSum < 0)/*当前子列和为负*/
			ThisSum = 0;/*不可能使后面部分和增大,抛弃之前的数*/
	}
	return MaxSum;
}

显而易见,时间复杂度为O(n),应该算是能得到的最快算法了。

过程如下:

 

 (图片、内容来自,陈越老师主编的《数据结构》)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值