最大字段和问题

最大字段和的思想是将字段分为两部分,即将数组平均分为两部分,那么最大字段和的问题分为三种:

(1)最大字段和在数组的第一部分

(2)最大字段和在数组的第二部分

(3)最大字段和在数组的“中间”部分,即以数组的中间数为起点向数组的两端扩展得到的最大子段和

这个时候就要用到递归的思想,最开始就分为这三种情况,当求第一种情况时,就又要将“一半”数组分为三种情况讨论,如此递归。针对第三种情况,我采用的思想是从数组中间那个书开始向两边扩展分别求和,并且记录在每个数所求的和(左半部分从中间那个数开始向前算,右半部分从中间那个数的后面那个数开始算),然后求出左半部分的最大值和右半部分的最大值并且记录下两边取得最大和的元素的位置,然后在整合两边的最大字段和,最后再将三种情况下的值进行比较。

import org.w3c.dom.css.ElementCSSInlineStyle;

//最大字段和问题的思路为:将最大字段分为两半,则有三种情况,一种为第一部分的子段最大,第二种为第二部分的最大,
//第三种是前后两端的中间部分最大,这种情况下则从子段的中间部分分别往前后两部分求得其最大值再相加
//最后比较三种情况的最大值,即求得最大字段,并输出。
public class maxAdd {

	//public int []a= {3,-5,2,3,-4,8,4,-6,-8,9,2,-4,7,6};   //定义待求的数组
	public int[] add (int[] s)
	{
		int []a=new int [5];
		if(s.length==1)
		{
			return s;
		}
		
		else  if(s.length==2) 
		 {
			 int []x=new int [1];
			if(s[0]>s[1])
			{
				if(s[1]>=0)
				{
					return s;
				}
				else 
				{
					
					x[0]=s[0];
					return x;
				}
			}
			else
			{
				if(s[0]>=0)
				{
					return s;
				}
				else
				{
					x[0]=s[1];
					return x;
				}
			}
			
		}
		//当数组元素大于等于三个的时候
		else
		 {
			//将数组对半,并且将数组的两部分分别赋值给另外一个数组作为参数传递给方法
			 int m,n;
			 m=s.length/2;
			 n=s.length-m;
			 int []p=new int [m];
			 int []q=new int [n];
			 for(int i=0;i<m;i++)
			 {
				 p[i]=s[i];    //依次赋值
			 }
			 for(int j=0;j<n;j++)
			 {
				 q[j]=s[j+m];	//依次赋值
			 }
			 //求出子段中的最大字段和,并赋值给新的数组num1和num2
			 int []num1=add(p);
			 int []num2=add(q);
			 //最大字段和已经求出,现在要求的是这个字段和的值,即分别对两个数组进行元素求和
			 int e,r;e=r=0;
			 for(int i=0;i<num1.length;i++)
			 {
				 e+=num1[i];	//数组num1元素的和
			 }
			 for(int j=0;j<num2.length;j++)
			 {
				 r+=num2[j];	//数组num2元素的和
			 }
			 
			 //两个子部分的最大子段和已经求出,现在要求的是数组s从中间开始向两边扩展的字段和
			 //重新设置一个数组,数组个数等于s的个数,记录从s中间元素开始,依次向两边扩展累计的和
			 //如数组t,第m-1个元素为s[m-1],第m-2各元素为s[m-1]+s[m-2],而第m个元素的值为s[m],第m+1各元素的值为s[m]+s[m+1],然后求出两部分中最大的值相加
			int []t=new int [s.length];
			t[m-1]=s[m-1];
			t[m]=s[m];
			for(int i=m-2;i>=0;i--)
			{
				t[i]=s[i]+t[i+1];	//在m之前的元素的值都是s[i]加上t[i+1],即加上数组t中的后面的那个数
			}
			for(int j=m+1;j<s.length;j++)
			{
				t[j]=t[j-1]+s[j];
			}
			 //数组s中从中间起前后两部分的最大段和基本已经求出,现在要求的是在这个数组中前后两端分别在哪个位置取得最大值,同时需要两个变量来记录这两个位置
			int max1=0,max2=0;
			int x=0,y=m;
			for(int i=0;i<m;i++)
			{
				if(t[i]>max1)
				{
					max1=t[i];
					x=i;
				}
			}
			for(int j=m;j<s.length;j++)
			{
				if(t[j]>max2)
				{
					max2=t[j];
					y=j;
				}
			}
			int []g=new int [y-x+1];
			for(int i=0;i<g.length;i++)
			{
				g[i]=s[x+i];
			}
			//已经求出该数组的最大值,现在比较三者中的最大值,并且数组该最大值组成的数组
			int  max;
			max=max1+max2;
			if(e>r)
			{
				if(e>max||r>max)
				{
					return num1;
				}
				else {
					return g;
				}
			}
			else
			{
				if(e>max||r>max)
				{
					return num2;
				}
				else
				{
					return g;
				}
			} 
		 }
		
	
	}
	public static void main(String []args)
	{
		int []a = {3,-5,2,3,-4,8};
		maxAdd pAdd=new maxAdd();
		int []b=pAdd.add(a);
		int sum=0;
		System.out.print("最大字段和的字段为:");
		for(int i=0;i<b.length;i++)
		{
			sum+=b[i];
			System.out.print(b[i]+" ");
		}
		System.out.println("\n"+"和为:"+sum);
		
		
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值