最大子列和问题
我们通过四种算法分别通过java语言解决最大子列和问题
问题来源:MOOC-浙江大学-数据结构-1.3应用实例(最大子列和问题)
传送门
//最大子列和问题
import java.util.*;
public class Main{
public static void main(String [] args) {
Scanner scan =new Scanner(System.in);
int thissum,maxsum=0;
int n=scan.nextInt();
int []a=new int[n];
for(int i=0;i<n;i++)
a[i]=scan.nextInt();
for(int j=0;j<a.length;j++) {
for(int k=j;k<a.length;k++){
thissum=0;
for(int h=j;h<=k;h++) {
thissum=thissum+a[h];
if(thissum>maxsum) {
maxsum=thissum;
}
}
}
}
System.out.println("sum="+maxsum);
}
}
运行结果:
以上算法时间复杂度较大,为(N^ 3)不利于大数据运算,通过观察,我们能发现,以上代码中的第三重循环可删除,故我们采用以下算法,其时间复杂度为(N^2):
package asd;
import java.util.*;
public class gg{
public static void main(String [] args) {
Scanner scan =new Scanner(System.in);
int thissum,maxsum=0;
int n=scan.nextInt();
int []a=new int [n];
for (int i = 0; i < n; i++) {
a[i]=scan.nextInt();
}
for (int i = 0; i <a.length; i++) {
thissum=0;
for (int j = i; j < a.length; j++) {
thissum+=a[j];
if(thissum>maxsum) {
maxsum=thissum;
}
}
}
System.out.println("sum="+maxsum);
}
}
运行结果:
以上算法时间复杂度为(N^2),但是当处理大数据时,仍不使用,所以我们可以再次简化代码,采用分而治之的思想方法,从而可以将时间复杂度减少为:(N*lgN):
分而治之的核心思想是将数组分块治理,首先二分数组,然后分别求解出左侧最大子列和以及右侧最大子列和,再将左侧最大子列和与右侧最大子列和与两者之和进行比较,从而能得出整体最大子列和。
import java.util.*;
public class Main{
public static void main(String [] args) {
Scanner scan =new Scanner (System.in);
int n=scan.nextInt();
int []a=new int [n];
for (int i = 0; i < a.length; i++)
a[i]=scan.nextInt();
int max=Sort(a, 0, n-1);
System.out.println("sum="+max);
}
public static int Sort(int[] a, int left, int right) {
// TODO Auto-generated method stub
int maxleft,maxright;
if(left==right) {//判断子列是否只有一个元素;
if(left>0) {
return a[left];
}
else
return 0;
}
int midnum=(left+right)/2;
maxleft=Sort(a,left,midnum);
maxright=Sort(a,midnum+1,right);
int thisleftnum = 0,thisrightnum=0;//左边的最大子列和
int maxleftsum = 0, maxrightsum = 0;//左边的和,右边的和
for(int i=midnum;i>=left;i--) {//左侧最大子列和
maxleftsum+=a[i];
if(maxleftsum>thisleftnum) {
thisleftnum=maxleftsum;
}
}
for(int j=midnum+1;j<=right;j++) {//右侧最大子列和
maxrightsum+=a[j];
if(maxrightsum>thisrightnum) {
thisrightnum=maxrightsum;
}
}
return max(maxleft,maxright,thisleftnum+thisrightnum);
}
public static int max(int a, int b, int c) {
// TODO Auto-generated method stub
int t;
if(a>b){t=a;a=b;b=t;}
/*交换x,y的值*/
if(a>c){t=c;c=a;a=t;}
/*交换x,z的值*/
if(b>c){t=b;b=c;c=t;}
return c;
}
}
运行结果:
5
2 3 4 -9 2
sum=9
通过观察,我们发现,这还不是最简单的算法,我们通过“在线处理算法”,所以只需要将数组遍历一遍,得出结果。
从而能够将时间复杂度降为O(N):
package asd;
import java.util.*;
public class gg{
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int thissum = 0,maxsum=0;
int n=scan.nextInt();
int []a=new int [n];
for (int i = 0; i < a.length; i++) {
a[i]=scan.nextInt();
}
for (int i = 0; i < a.length; i++) {
thissum+=a[i];
if(thissum>maxsum) {
maxsum=thissum;
}
else if(thissum<0) {//当小于0的时候,直接排除
thissum=0;
}
}
System.out.println("sum="+maxsum);
}
}
运行结果:
6
2 3 4 5 -2 -3
sum=14
由于必须要将数组遍历一遍,所以时间复杂度最低为O(N),通过以上解法。我们能够得出最为简便的算法:在线处理,从而能够高效率的解决最大子列和问题。