最大子序列

給定一個含有正負數的數組,求這個數組中連着的數組相加起來的最大和。最大和至少爲0,即沒有任何數相加。

1.最大子序列算法複雜度爲O(n^3)

public static int maxSubSum1(int[] a)
{
	int maxSum = 0;
	for(int i = 0; i<a.length;i++)
	    for(j = i;j<a.length;j++){
	    	int thisSum = 0;
	    	for(int k =i;k<=j;k++)
	    		thisSum +=a[k];
	    	if(thisSum > maxSum)
	    		maxSum = thisSum;
	    }
	return maxSum;
}

2.改進算法,時間複雜度爲O(n^2)

public static int maxSum2(int[] a)
{
	int maxSum = 0;
	for(int i = 0;i<a.length;i++)
	{
		int thisSum = 0;
		for(int j = i;j<a.length;j++)
		{
			thisSum +=a[j];
			if(thisSum >maxSum)
				maxSum = thisSum;
		}
	}
	return maxSum;
}


3.進階改進算法,時間複雜度O(N logN)

該方法採用一種“分治”策略,其思想是把問題分成兩個大致相等的子問題,然後遞歸地對他們求解,這就是“分”的部分,“治”階段將兩個子問題的解修補到一起並可能在做些少量的附加工作,最後得到整個問題的解。

在我們的例子中,最大子序列和可能在三處出現,或者整個出現在輸入數據的左半部,或者整個出現在右半部,或者跨越輸入數據的中部從而位於左右兩半部分之中,前兩種情況可以遞歸求解。第三種情況的最大和可以通過求出前半部分(包含前半部分最後一個元素)的最大和以及後半部分(包含後半部分第一個元素)的最大和而得到。此時將這兩個和相加。

private static int maxSumRec(int[] a,int left, int right)
{
	if(left == right)
		if(a[left] > 0)
			return a[left]
		else
			return 0;

	int center =(left +right) /2;
	int maxLeftSum = maxSum(a,left,center);
	int maxRightSum = maxSumRec(a, center + 1;right);

	int maxLeftBorderSum = 0, leftBorderSum = 0;
	for(int i = center; i>= left; i--)
	{
		leftBorderSum += a[i];
		if(leftBorderSum > maxLeftBorderSum)
			maxLeftBorderSum = leftBorderSum;
	}

	int maxRightBorderSum = 0;rightBorderSum = 0;
	for(int i = center +1;i<= right;i++)
	{
		rightBorderSum += a[i];
		if(rightBorderSum >maxRightBorderSum)
			maxRightBorderSum = rightBorderSum;
	}

	return max(maxLeftSum,maxRightSum,maxLeftBorderSum+maxRightBorderSum);
}

public static int maxSubSum3(int[] a)
{
	return maxSumRec(a,0,a.length-1);
}


4.終極改進算法,時間複雜度O(n)

它只對數據進行一次掃描,一旦a[i]被讀入並被處理,他就不再需要被記憶。

如果a[i]是負的,那麼它不可能代表最優序列的起點,類似的,任何負的子序列不可能成爲最優子序列的前綴。如果a[i]到a[j]的子序列是負的,那麼可以推進i.

關鍵的結論是,我們不僅能夠把i推進到i+1,而且實際上還可以把它一直推進到j+1.爲了看清楚這一點,另p爲i+1到j之間的任一下標。開始於下標p的任意子序列都不大於在下標i開始幷包含從a[i]到a[p-1]的子序列的對應的子序列,因爲後面這個子序列不是負的(j是使得從下標i開始其值成爲負值的序列的第一個下標)。因此,把i推進到j+1是沒有風險的。



public static int maxSubSum3(int[] a)
{
	return maxSumRec(a,0,a.length-1);
}

public static int maxSubSum4(int[] a)
{
	int maxSum = 0,thisSum = 0;
	for(int j = 0; j<a.length; j++)
	{
		thisSum += a[j];
		if(thisSum >maxSum)
			maxSum = thisSum;
		else if(thisSum < 0)
			thisSum = 0;
	}
	return maxSum;
}











發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章