问题描述:给定(可能存在负值)整数A1,A2.....An,求最大子序列和。如果所有的整数均为负数,则最大子序列和为0.
列如:对于输入-2,11,-4,13,-5,-2,该输入的最大子序列和为20(11-4+13).
现在我们将叙述四个算法来求解最大子序列和问题。
1. 该算法是使用穷举法来尝试所有的可能 算法如下
public static int maxSubSum1(int [] a) { int maxSum=0; for(int i=0;i<a.length;i++) { for(int 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; }该算法的时间复杂度为O(N3)
第一个算法的第三个for循环中有大量不必要的重复计算,如:计算i到j的和,然而i到j-1的和在前一次的循环中已经计算过,无需重复计算,故该for循环可以去掉
算法2
public static int maxSubSum2(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; }该算法的复杂度为O(N2).
对于这个问题有一个递归解法,该方法采用一种分治的策略。其想法是把问题分为两个大致相等的子问题。然后递归地对他们求解,在使用分治的时候,最大子序列可能出现在三个不同的部位,可能出现在左半部分,可能出现在右半部分,也可能出现在出现在左右交界处,前两种情况可以递归求解,第三种情况的最大和可以通过求出前半部分的最大和以及后半部分的最大和,然后将两个结果进行相加,考虑下列输入:
其中前半部分的最大和为6(从元素A1到A3)而后半部分的最大子序列和为8(从元素A6到A7)
前半部分包含其最后一个元素的最大和为4,而后半部分包含其第一个元素的最大和为7,因此跨越这两个部分且通过中间的最大和为11.
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=maxSumRec(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); } private static int max(int left,int right,int middle) { int max=0; if(max<=left)max=left; if(max<=right)max=right; if(max<=middle)max=middle; return max; }
private static int maxSubSum4(int [] a) { int maxSum=0;thisSum=0; for(int j=0;j<a.lemgth;j++) { thisSum +=a[j]; if(thisSum>maxSum)maxSum=thisSum; else if(thisSum<0)thisSum=0; } return maxSum; }
算法四的时间复杂度为O(N)