最大子序列求和的問題就是對於給定的整數數列(裏面可能有負數)A1,A2,…AN,求Ai到Ak的和的最大值。
例如 -2,11,-4,13,-5,-2 這個數列的最大子序列和就是11-4+13=20。下面用四種方法實現這個功能。時間複雜度依次減小。
- 用三個for循環
public class MaxSubSum {
public static void main(String[] args) {
int a[]={-2,11,-4,13,-5,-2};
int maxsum=0,i,j,k;
for(i=0;i<a.length;i++){
for(j=i;j<a.length;j++){
int thissum=0;
for(k=i;k<=j;k++){
thissum=thissum+a[k];
if(thissum>maxsum){
maxsum=thissum;
}
}
}
}
System.out.println(maxsum);
}
}
很顯然這個的時間複雜度是O(N3)
- 用兩個for循環,上面的第三個for是可以不用的
public class MaxSubSum2 {
public static void main(String[] args) {
int a[]={-2,11,-4,13,-5,-2};
int maxsum=0,i,j;
for(i=0;i<a.length;i++){
int thissum=0;
for(j=i;j<a.length;j++){
thissum=thissum+a[j];
if(thissum>maxsum){
maxsum=thissum;
}
}
}
System.out.println(maxsum);
}
}
少了一個for,時間複雜度爲O(N2)
- 用遞歸,程序較多一點
public class MaxSubSum3 {
public int maxsum(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=maxsum(a,center+1,right); //右邊遞歸
int maxleftbodersum=0,leftbodersum=0;
for(int i=center;i>=left;i--){
leftbodersum=leftbodersum+a[i];
if(leftbodersum>maxleftbodersum){
maxleftbodersum=leftbodersum;
}
}
int maxrightbodersum=0,rightbodersum=0;
for(int i=center+1;i<=right;i++){
rightbodersum=rightbodersum+a[i];
if(rightbodersum>maxrightbodersum){
maxrightbodersum=rightbodersum;
}
}
return max(maxleftsum,maxrightsum,maxleftbodersum+maxrightbodersum);
}
private int max(int x, int y, int z) {
int temp,result;
if(x>y){
temp=x;
}
else{
temp=y;
}
if(temp>z){
result=temp;
}
else{
result=z;
}
return result;
}
/**
* @param args
*/
public static void main(String[] args) {
int a[]={-2,11,-4,13,-5,-2};
MaxSubSum3 max=new MaxSubSum3();
max.maxsum(a, 0, a.length-1);
System.out.println(max.maxsum(a, 0, a.length-1));
}
}
這兩個for是找出含有中間項的和的最大值。這個算法遞歸的是每次變成N/2,然後for循環的時間複雜度爲O(N),整個算法的時間複雜度是O(NlogN)。
- 最後一個也是最優的算法了吧 ,因爲不需要知道這個子序列在哪裏,只需要知道最後的值,子序列中第一項如果是負數那麼肯定不能是最大的了。
public class MaxSubSum4
{
public static void main(String[] args) {
int a[]={-2,11,-4,13,-5,-2};
int maxsum=0,thissum=0;
for(int i=0;i<a.length;i++){
thissum=thissum+a[i];
if(thissum>maxsum){
maxsum=thissum;
}
else if(thissum<0){
thissum=0;
}
}
System.out.println(maxsum);
}
}
這個只有一個for循環,所以時間複雜度爲O(N)。