二分法之最大子段和

1.问题描述:给定一个数组,找出其中可以构成最大数的子段,子段和是由连续的子段构成的;给定有n个整数(可能为负整数)组成的序列a1,a2,...,an,求该序列连续的子段和的最大值。

2.设计思路:对于一个连续的子段和,如果把数组一分为二,那么最大的和有三种情况:在center的左边、右边,左右结合;所以只需要分别求出这三种情况的和,进行比较得到最大的和即可;其中的递归出口为right=left,也就是小子段中只剩下一个元素时结束递归。

3.代码:

/*二分法解决最大子段和问题*/
#include<stdio.h>
#include<math.h>
int array[6]={-20,11,-4,13,-5,-2};				//定义有六个元素的数组,保存信息 
int array2[9]={-1,4,-3,1,5,-1,4,-5,2};
int bigger(int a,int b)				//自定义一个求解最大数的函数 
{
	return a>b ? a:b;
 } 
int SubSegmentSum(int array[],int left,int right)
{
	int sum=0,leftsum=0,midsum=0,rightsum=0;         //分别保存最后的sum、左边、中间、右边的最大子段和 
	int center; 					  //中间分界线 
	int s1,lefts,s2,rights;			//记录最大子段和为两边时的和 
	if(left==right)					  
	{
		sum=array[left];			//只有一个元素时sum=array[left]或者array[right] 
	 } 
	 else{
	 	center=(left+right)/2;
	 	//printf(" %d\n",center);
		 leftsum= SubSegmentSum(array,left,center);			//求左边的最大子段和
		 rightsum=SubSegmentSum(array,center+1,right);			//求右边的最大子段和
		 s1=0,lefts=0;
		 for(int i=center;i>=left;i--)					//从中间开始往左边求最大子段和 
		 {
		 	lefts+=array[i];
		 	if(lefts>s1)
		 	{
		 		s1=lefts;
			 }
		  } 
		  s2=0,rights=0;
		  for(int i=center+1;i<=right;i++)				//从中间开始往右边求最大子段和 
		  {
		  	rights+=array[i];
		  	if(rights>s2)
		  	{
		  		s2=rights;
			  }
		  }
		  midsum=s1+s2;						//中间的最大子段和  
		  sum=bigger(bigger(leftsum,rightsum),midsum);		//求解最大子段和 
	 }
	 return sum;
}
int main()
{
	int sum1=SubSegmentSum(array,0,5);
	int sum2=SubSegmentSum(array2,0,8);
	printf("%d\n",sum1);
	printf("%d\n",sum2);
	return 0;
}

4.运行结果:

5.总结:

最大子段和问题,关键是清楚连续的最大子段和的三种情况:左边、右边和左边加右边,分别求出三种情况下的最大子段和,进行比较即可以得到最大的子段和。

对左右结合情况的理解:左右结合的最大和的值S,一定是从中间位置mid为起点,往左的最大子段和S1,与从中间位置mid为起点,往右的最大子段和S2,两者之和。即S=S1+S2。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值