1. 程式人生 > >求最大子序列之和的四種方法

求最大子序列之和的四種方法

四種求最大子序列和的方法,效率一個比一個高。

方法二是方法一的改進

方法三是採用分治的思想,編寫遞迴函式

方法四 最為巧妙,程式碼少,效率高,邏輯清晰

對原書中的程式碼做了一小點修改,能處理負數陣列(結果為最小的負數)

附上程式碼

package chapter2;
import java.util.Random;
public class maxSubSum 
{
/*-------------------------------方法1 --------------------------------*/
    public  int maxSubSum1(int[] a)//方法1 
	{
    	    //最笨的方法,分別以每個元素為起點 計算每一種長度的和
		int sum=a[0],sumMax=a[0];
		for (int i = 0; i < a.length; i++)//每一個元素為起點 
		{
			
			for (int j = i; j < a.length; j++)//每一種子序列長度 
			{
				sum=a[i];
				for(int k=i+1;k<=j;k++)//求和
					sum+=a[k];
				if (sumMax<sum)//比較更新Max
				{
					sumMax=sum;
				}
			}
		}
		return sumMax;
	}
/*-------------------------------方法2 --------------------------------*/
public int maxSubSum2(int[] a)//方法二
{
	//方法一的改進,通過一個for迴圈直接得出 某個元素為起點的所有子序列的最大和
	int sum=0,sumMax;
	sumMax=a[0];
	for (int i = 0; i < a.length; i++)//選取每一個元素為起點
	{
		sum=0;
		for (int j = i; j < a.length; j++)//比較每一種序列的和
		{
			sum+=a[j];
			if (sum>sumMax) 
				sumMax=sum;
		}
		
	}
	return sumMax;
}
/*-------------------------------方法3 --------------------------------*/
public int maxSubSum3(int[] a,int left,int right)//方法三
{
	//分治策略
	//每次把陣列分成左右兩部分,
	//最大子序列和可能在三處出現,整個序列出現在左邊或者右邊,或者跨越中部
	
	if (left==right) //基本情況,left=right,只有一個元素
		return a[left];
	
	int center=(left+right)/2;//遞迴,繼續分成左右兩部分,
	int maxLeftSum=maxSubSum3(a, left, center);//返回左邊的最大和
	int maxrightSum=maxSubSum3(a, center+1, right);//返回右邊的最大和
	
	//計算從center為起點,分別向左和向右的最大序列和
	//center向左的最大子序列和
	int maxLeftBorderSum=a[center],leftBorderSum=a[center];
	for (int i = center-1; i >= left; i--) 
	{
		leftBorderSum+=a[i];
		if (leftBorderSum>maxLeftBorderSum) 
			maxLeftBorderSum=leftBorderSum;
	}
	//center向右的最大子序列和
	int maxrightBorderSum=a[center+1],rightBorderSum=a[center+1];
	for (int i = center+2; i <=right; i++) 
	{
		rightBorderSum+=a[i];
		if (rightBorderSum>maxrightBorderSum) 
			maxrightBorderSum=rightBorderSum;
	}
	//返回三種情況的最大值(整個在左邊,整個在右邊,跨區域)
	
	int max;
	max=maxLeftSum>maxrightSum? maxLeftSum:maxrightSum;
	max=max>maxLeftBorderSum+maxrightBorderSum?max:maxLeftBorderSum+maxrightBorderSum;
	return max;
}
/*-------------------------------方法4 --------------------------------*/
	public int maxSubSum4(int[] a)//方法四
	{
		//效率最高,程式碼最簡單
		//思路:小於0的子序列(包括單個元素的情況)比較sumMax後直接拋棄,sum重置為0,繼續累加
		int sum=a[0],sumMax=a[0];
		for (int i = 1; i < a.length; i++)
		{
			sum+=a[i];
			if (sum>sumMax) 
				sumMax=sum;
			if (sum<0) 
				sum=0;	
		}
		return sumMax;
	}
	public static void main(String[] args) 
	{
		
		int[] a=new int[1000];
		for (int i = 0; i < a.length; i++)//隨機數給陣列賦值
		{
			a[i]=(int )( (0.5-Math.random())*100);
			if (a[i]==0) 
				a[i]=-8;
		}
		maxSubSum test=new maxSubSum();
		
		System.out.println(test.maxSubSum4(a));
		System.out.println(test.maxSubSum3(a,0,999));
		System.out.println(test.maxSubSum2(a));
		System.out.println(test.maxSubSum1(a));
	}
}