給定一個含有正負數的數組,求這個數組中連着的數組相加起來的最大和。最大和至少爲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;
}