public class MaxSegmentSum {
/*
给定由n个整数组成的序列a[1],a[2],a[3]......a[n],求该序列形如a[i]+a[i+1]+...+a[j]的子段和的
最大值,当所有参数均为负数时定义其最大子段和为0。故所求的最优值为:
max{0,a[i]+a[i+1]+...+a[j]},1<=i<=j<=n
例如:(a1,a2,a3,a4,a5,a6)=(-2,11,-4,13,-5,-2)时,最大子段和为20。
*/
/*最大子段和的简单算法
从这个算法来看,它所需的时间为O(n^3)
*/
public static int getMaxSegmentSumOne(int[] array){
int n=array.length;
int besti=0,bestj=0;
int sum=0;
for(int i=0;i<n;i++){
for(int j=i;j<n;j++){
int thisSum=0;
for(int k=i;k<=j;k++)
thisSum+=array[k];
if(thisSum>sum){
sum=thisSum;
besti=i;
bestj=j;
}
}
}
System.out.println("数组第"+(besti+1)+"个到"+(bestj+1)+"个数最大,最大和为"+sum);
return sum;
}
/*
(a[i]+a[i+1]+...+a[j])=a[j]+(a[i]+a[i+1]+...+a[j-1])
上述只需O(n^2)
*/
public static int getMaxSegmentSumTwo(int[] array){
int n=array.length;
int besti=0,bestj=0;
int sum=0;
for(int i=0;i<n;i++){
int thisSum=0;
for(int j=i;j<n;j++){
thisSum+=array[j];
if(thisSum>sum){
sum=thisSum;
besti=i;
bestj=j;
}
}
}
System.out.println("数组第"+(besti+1)+"个到"+(bestj+1)+"个数最大,最大和为"+sum);
return sum;
}
/*
最大子段和的分治算法
我们可以将a[1:n]分为a[1:n/2]和a[n/2+1:n],分别求出这两段的最大子段和
(1)a[1:n]的最大子段和与a[1:n/2]的最大子段和
(2)a[1:n]的最大子段和与a[n/2+1:n]的最大子段和
(3)a[1:n]的最大子段和与a[i]+a[i+1]...a[j],且1<=i<=n/2,n/2+1<=j<=n
对应的时间复杂度T(n)
T(n)=2T(n/2)+O(n),故时间复杂度为T(n)=O(nlogn)
*/
public static int getMaxSegmentSumThree(int[] array,int left,int right){//此时可以为array[left],也可以为array[right]
//System.out.println("left="+left+" right="+right);
int sum=0;
if(left==right){
//System.out.println("相等了="+left);
sum=array[left]>0?array[left]:0;
}else{
int center=(left+right)/2;
int leftsum=getMaxSegmentSumThree(array,left,center);
int rightsum=getMaxSegmentSumThree(array,center+1,right);
int s1=0;
int lefts=0;
for(int i=center;i>=left;i--){
lefts+=array[i];
if(lefts>s1){
s1=lefts;
}
}
int s2=0;
int rights=0;
for(int i=center+1;i<=right;i++){
rights+=array[i];
if(rights>s2){
s2=rights;
}
}
sum=s1+s2;
if(sum<leftsum)
sum=leftsum;
if(sum<rightsum)
sum=rightsum;
}
return sum;
}
/*
最大字段和的动态规划算法
b[j]=max(a[i]+a[i+1]+...+a[j]),1<=i<=j且1<=j<=n,则所求的最大子段和为max(b[j]),1<=j<=n
由b[j]定义知:当b[j-1]>=0时,b[j]=b[j-1]+a[j],
否则,b[j-1]<0,时,b[j]=max(a[i]+a[i+1]+...+a[j])=a[j]
故动态规划为:
b[j]=max(b[j-1]+a[j],a[j]),1<=j<=n
*/
public static int getMaxSegmentSumFour(int[] array){ //只需求出最大的b[j],即max(b[j])
int sum=0,b=0;
for(int i=0;i<array.length;i++){
if(b>0){
b+=array[i];
}else{
b=array[i];
}
if(b>sum){
sum=b;
}
}
return sum;
}
public static void main(String[] args) {
int[] array={-2,11,-4,13,-5,-2};
int maxSegment=getMaxSegmentSumOne(array);
System.out.println("maxSegmentOne="+maxSegment);
maxSegment=getMaxSegmentSumTwo(array);
System.out.println("maxSegmentTwo="+maxSegment);
maxSegment=getMaxSegmentSumThree(array,0,array.length-1);
System.out.println("maxSegmentThree="+maxSegment);
maxSegment=getMaxSegmentSumFour(array);
System.out.println("getMaxSegmentSumFour="+maxSegment);
}
}
/*
给定由n个整数组成的序列a[1],a[2],a[3]......a[n],求该序列形如a[i]+a[i+1]+...+a[j]的子段和的
最大值,当所有参数均为负数时定义其最大子段和为0。故所求的最优值为:
max{0,a[i]+a[i+1]+...+a[j]},1<=i<=j<=n
例如:(a1,a2,a3,a4,a5,a6)=(-2,11,-4,13,-5,-2)时,最大子段和为20。
*/
/*最大子段和的简单算法
从这个算法来看,它所需的时间为O(n^3)
*/
public static int getMaxSegmentSumOne(int[] array){
int n=array.length;
int besti=0,bestj=0;
int sum=0;
for(int i=0;i<n;i++){
for(int j=i;j<n;j++){
int thisSum=0;
for(int k=i;k<=j;k++)
thisSum+=array[k];
if(thisSum>sum){
sum=thisSum;
besti=i;
bestj=j;
}
}
}
System.out.println("数组第"+(besti+1)+"个到"+(bestj+1)+"个数最大,最大和为"+sum);
return sum;
}
/*
(a[i]+a[i+1]+...+a[j])=a[j]+(a[i]+a[i+1]+...+a[j-1])
上述只需O(n^2)
*/
public static int getMaxSegmentSumTwo(int[] array){
int n=array.length;
int besti=0,bestj=0;
int sum=0;
for(int i=0;i<n;i++){
int thisSum=0;
for(int j=i;j<n;j++){
thisSum+=array[j];
if(thisSum>sum){
sum=thisSum;
besti=i;
bestj=j;
}
}
}
System.out.println("数组第"+(besti+1)+"个到"+(bestj+1)+"个数最大,最大和为"+sum);
return sum;
}
/*
最大子段和的分治算法
我们可以将a[1:n]分为a[1:n/2]和a[n/2+1:n],分别求出这两段的最大子段和
(1)a[1:n]的最大子段和与a[1:n/2]的最大子段和
(2)a[1:n]的最大子段和与a[n/2+1:n]的最大子段和
(3)a[1:n]的最大子段和与a[i]+a[i+1]...a[j],且1<=i<=n/2,n/2+1<=j<=n
对应的时间复杂度T(n)
T(n)=2T(n/2)+O(n),故时间复杂度为T(n)=O(nlogn)
*/
public static int getMaxSegmentSumThree(int[] array,int left,int right){//此时可以为array[left],也可以为array[right]
//System.out.println("left="+left+" right="+right);
int sum=0;
if(left==right){
//System.out.println("相等了="+left);
sum=array[left]>0?array[left]:0;
}else{
int center=(left+right)/2;
int leftsum=getMaxSegmentSumThree(array,left,center);
int rightsum=getMaxSegmentSumThree(array,center+1,right);
int s1=0;
int lefts=0;
for(int i=center;i>=left;i--){
lefts+=array[i];
if(lefts>s1){
s1=lefts;
}
}
int s2=0;
int rights=0;
for(int i=center+1;i<=right;i++){
rights+=array[i];
if(rights>s2){
s2=rights;
}
}
sum=s1+s2;
if(sum<leftsum)
sum=leftsum;
if(sum<rightsum)
sum=rightsum;
}
return sum;
}
/*
最大字段和的动态规划算法
b[j]=max(a[i]+a[i+1]+...+a[j]),1<=i<=j且1<=j<=n,则所求的最大子段和为max(b[j]),1<=j<=n
由b[j]定义知:当b[j-1]>=0时,b[j]=b[j-1]+a[j],
否则,b[j-1]<0,时,b[j]=max(a[i]+a[i+1]+...+a[j])=a[j]
故动态规划为:
b[j]=max(b[j-1]+a[j],a[j]),1<=j<=n
*/
public static int getMaxSegmentSumFour(int[] array){ //只需求出最大的b[j],即max(b[j])
int sum=0,b=0;
for(int i=0;i<array.length;i++){
if(b>0){
b+=array[i];
}else{
b=array[i];
}
if(b>sum){
sum=b;
}
}
return sum;
}
public static void main(String[] args) {
int[] array={-2,11,-4,13,-5,-2};
int maxSegment=getMaxSegmentSumOne(array);
System.out.println("maxSegmentOne="+maxSegment);
maxSegment=getMaxSegmentSumTwo(array);
System.out.println("maxSegmentTwo="+maxSegment);
maxSegment=getMaxSegmentSumThree(array,0,array.length-1);
System.out.println("maxSegmentThree="+maxSegment);
maxSegment=getMaxSegmentSumFour(array);
System.out.println("getMaxSegmentSumFour="+maxSegment);
}
}