分治算法——求最大字段和

LGOODL 2022-09-25 16:56:21

一、问题描述

给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整数均为负数时,定义子段和为0。

输入格式:

输入有两行:

第一行是n值(1<=n<=10000);

第二行是n个整数。

输出格式:

输出最大子段和。

输入样例:

在这里给出一组输入。例如:

6

-2 11 -4 13 -5 -2

输出样例:

在这里给出相应的输出。例如:

20

二、解决思路

利用分治法来解决,题目是要求在数组中寻找最大字段和,(用递归来写)如果只有一个元素(n=0),只需要判断该元素是否大于零,如果大于零的话就返回该元素,如果不是的话就返回零;如果元素个数多于一个的话(n>1),就采用二分,将数组一分为二,在左右两段数组寻找最大字段和,那么左数组和右数组就分别获得一个最大字段和。还有一种情况,就是最大字段和既不在数组左边,也不在数组右边,而是在数组中间。那就需要从数组中间的元素向两边求出这个最大字段和。由上就求到了三个最大字段和,再较大小左、中、右的最大字段和的大小返回最大的一个字段和即可。

代码如下:

#include <iostream>
using namespace std;
int a[10000];
int n;
int max(int l,int r)
{
	int maxL,maxR,maxM;//左数组的最大字段和、左数组的最大字段和、中间的最大字段和 
	if(r==l)//如果只有一个元素,大于0返回该元素,小于0返回0 
	{
		if(a[l]>=0)
		return a[l];
		else
		return 0;
	}
	int mid=(r+l)/2;
	maxL=max(l,mid);//左数组求最大子段和 
	maxR=max(mid+1,r);//右数组求最大字段和 
	
	int flagL=0,flagR=0,m_maxL=0,m_maxR=0;//求中间的最大字段和 
	for(int i=mid;i>=l;i--) 
	{
		flagL+=a[i];
		if(flagL>m_maxL)
		m_maxL=flagL;
	}
	for(int i=mid+1;i<=r;i++)
	{
		flagR+=a[i];
		if(flagR>m_maxR)
		m_maxR=flagR;
	}
	maxM=m_maxR+m_maxL;
	
	if(maxL>maxR && maxL>maxM)
	return maxL;
	else if(maxR>maxL && maxR>maxM)
	return maxR;
	else if(maxM>maxL && maxM>maxR)
	return maxM; 
}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	cin>>a[i];
	cout<<max(0,n-1)<<endl;
	return 0;
}

时间复杂度:划分的时间复杂度是O(1),求解子问题复杂度为2T(n/2),求解中间最大字段和的是O(n),根据主定理,所以时间复杂度是O(nlog n)。

三、对于分治法的收获

分治法是将一个难以解决的大问题分割成一些规模较小的相同问题,以便各个击破,分而治之。反复用分治手段,可以使子问题与原问题一致但是规模却不断变小,最终子问题缩小到很容易解决。我学了分治法后,最直接的体会就是写的代码简洁易懂,通过递归调用自身,减少规模,使子问题比较容易解决。比如本题求最大字段和,分派问题,快速排序,合并排序等等。

...全文
295 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

434

社区成员

发帖
与我相关
我的任务
社区描述
广东外语外贸大学信息科学与技术学院
算法 高校
社区管理员
  • brisksea
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧