题目描述:给定一个序列a
,求它的最大连续字段和
方法一:三层for
循环遍历序列所有的字段,求出最大的字段和
public static void f1() {
int[] a = {-2,11,-4,13,-5,2};//原始数组
int max = -9999;//记录全局的最大连续子段和
for(int start=0;start<a.length;start++) {
for(int len=1;start+len<=a.length;len++) {
int sum=0;
for(int k=start;k<start+len;k++) {
sum=sum+a[k];
}
max=Math.max(max, sum);
System.out.printf("len=%2d a[%d-%d]sum=%2d\n",len,start,start+len,sum);
}
}
System.out.println("最大子段和应该是"+max);
}
运行结果:
len= 1 a[0-1]sum=-2
len= 2 a[0-2]sum= 9
len= 3 a[0-3]sum= 5
len= 4 a[0-4]sum=18
len= 5 a[0-5]sum=13
len= 6 a[0-6]sum=15
len= 1 a[1-2]sum=11
len= 2 a[1-3]sum= 7
len= 3 a[1-4]sum=20
len= 4 a[1-5]sum=15
len= 5 a[1-6]sum=17
len= 1 a[2-3]sum=-4
len= 2 a[2-4]sum= 9
len= 3 a[2-5]sum= 4
len= 4 a[2-6]sum= 6
len= 1 a[3-4]sum=13
len= 2 a[3-5]sum= 8
len= 3 a[3-6]sum=10
len= 1 a[4-5]sum=-5
len= 2 a[4-6]sum=-3
len= 1 a[5-6]sum= 2
最大子段和应该是20
方法二:穷举所有子段的起始点
public static void f2() {
int[] a = {-2,11,-4,13,-5,2};//原始数组
int max = -9999;//记录全局的最大连续子段和
for(int start=0;start<a.length;start++) {//穷举所有子段的起始点
int sum = 0;
for(int len=start;len<a.length;len++) {//从start开始,一直一次累计到最后
sum=sum+a[len];
max=Math.max(max, sum);//记录最大的那个
System.out.printf("len=%2d a[%d-%d]sum=%2d\n",len+1,start,len+1,sum);
}
}
System.out.println("最大字段和应该是"+max);
}
运行结果:
len= 1 a[0-1]sum=-2
len= 2 a[0-2]sum= 9
len= 3 a[0-3]sum= 5
len= 4 a[0-4]sum=18
len= 5 a[0-5]sum=13
len= 6 a[0-6]sum=15
len= 2 a[1-2]sum=11
len= 3 a[1-3]sum= 7
len= 4 a[1-4]sum=20
len= 5 a[1-5]sum=15
len= 6 a[1-6]sum=17
len= 3 a[2-3]sum=-4
len= 4 a[2-4]sum= 9
len= 5 a[2-5]sum= 4
len= 6 a[2-6]sum= 6
len= 4 a[3-4]sum=13
len= 5 a[3-5]sum= 8
len= 6 a[3-6]sum=10
len= 5 a[4-5]sum=-5
len= 6 a[4-6]sum=-3
len= 6 a[5-6]sum= 2
最大字段和应该是20
方法三:采用动态规划的方法, d p [ i ] = m a x dp[i]=max dp[i]=max{ d p [ i − 1 ] + a [ i ] , a [ i ] dp[i-1]+a[i],a[i] dp[i−1]+a[i],a[i]},
详细过程:以a={-2,11,-4,13,-5,2}为例,
①定义存放字段和的数组dp
, 大小和数组a
相等;
②dp[0]=a[0]=-2,max=-9999;
③i=1,dp[1]=max(dp[0]+a[1],a[1])=max(0+11,11)=11,max=11;
④i=2,dp[2]=max(dp[1]+a[2],a[2])=max(11-4,-4)=7,max=11;
⑤i=3,dp[3]=max(dp[2]+a[3],a[3])=max(7+13,13)=20,max=20;
⑥i=4,dp[4]=max(dp[3]+a[4],a[4])=max(20-5,-5)=15,max=20;
⑦i=5,dp[5]=max(dp[4]+a[5],a[5])=max(15+2,2)=17,max=20;
public static void f3() {
int[] a={-2,11,-4,13,-5,2};//原始数组
int[] dp=new int[a.length];
dp[0]=a[0];
int max=-9999;
for(int i=1;i<a.length;i++) {
dp[i]=Math.max(dp[i-1]+a[i], a[i]);
if(max<dp[i]) max=dp[i];
}
System.out.println(Arrays.toString(dp));
System.out.println(max);
}
运行结果:
[-2, 11, 7, 20, 15, 17]
20
方法四:遍历数组,当前的字段和大于0,则加上当前数a[i];否则就把当前数a[i]作为字段和(即i为字段的初始起点),然后继续向后遍历,直到数组结束。
详细过程:以a={-2,11,-4,13,-5,2}为例,
i=0,nowsum=-2,max=-2;
i=1,nowsum=11,max=11;
i=2,nowsum=11-4=7,max=11;
i=3,nowsum=7+13=20,max=20;
i=4,nowsum=20-5=15,max=20;
i=5,nowsum=15+2=17,max=20;
public static void f4() {
int[] a={-2,11,-4,13,-5,2};//原始数组
int nowsum=0;
int max=-9999;
for(int i=0;i<a.length;i++) {
if(nowsum>0) nowsum=nowsum+a[i];
else nowsum=a[i];
if(nowsum>max) max=nowsum;
System.out.println(nowsum);
}
System.out.println(max);
}
运行结果:
-2
11
7
20
15
17
20