给定一个含有正负数的数组,求这个数组中连着的数组相加起来的最大和。最大和至少为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;
}