要求
1.输入一个整型数组,数组里有正数也有负数。
2.数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
3.求所有子数组的和的最大值。要求时间复杂度为O(n)
思路及源代码
看到要求时,有点读不懂题。我以为是求数组中连续的数的和,比如-1 3 15 6 7 -9里求的是6+7=13,很显然我理解错了,真正题意求的是3+15+6+7=31。
首先不考虑时间复杂度为O(n),可以使用以下方法求得最大子数组的和。
package test; import java.util.Scanner; public class FindMaxArray { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int[] a = new int[10]; for(int i=0;i<10;i++) a[i] = sc.nextInt(); sc.close(); int[] max = new int[10]; //用于存储以对应位置起始的所有子数组和的最大值 int t; for(int i=0;i<10;i++) { t=0; for(int j=i;j<10;j++) { t += a[j]; if(max[i] < t) max[i] = t; } } t=0; for(int i=0;i<10;i++) if(t<max[i]) t=max[i]; System.out.println(“最大子数组的和为” + t); } }
本来以为所有最大子数组必定包含最大数,但是后来找到了一组反例,-12 13 -2 -13 3 11 1 -1 1 -1,最大子数组和为3+11+1=15,此时并未包含最大数13。后来发现如果以数块为基本单位,那么最大子数组必定包含最大数块,并且以最大数块为基点左右蔓延。
package test; import java.util.Scanner; public class FindMaxArray { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int[] a = new int[10]; for(int i=0;i<10;i++) a[i] = sc.nextInt(); sc.close(); int[] b = new int[10]; //数块数组 b[0] = a[0]; int j=0,max,maxnum=0; for(int i=1;i<10;i++) { if(a[i]<0 && b[j]>0) b[++j] = a[i]; else if(a[i]>0 && b[j]<0) b[++j] = a[i]; else if(a[i]<=0 && b[j]<0) b[j] += a[i]; else if(a[i]>=0 && b[j]>0) b[j] += a[i]; } if(b[0]<=0 && b[1]==0) { //所有数均小于等于0时 max=a[0]; for(int i=1;i<10;i++) if(max<a[i]) max=a[i]; System.out.println("最大子数组的和为:" + max); return; } max=b[0]; for(int i=0;i<=j;i++) if(max<b[i]) { max=b[i]; maxnum=i; } int t=0; for(int i=maxnum;i<=j-2;i+=2) { //从最大数块所在位置向右运算 t=t+b[i+1]+b[i+2]; //最大数块右方的数块和,如果存在大于0的,则可以加入最大子数组和的运算 if(t>0) { max+=t; t=0; } } t=0; for(int i=maxnum;i>=2;i-=2) { //从最大数块所在位置向左运算 t=t+b[i-1]+b[i-2]; //最大数块左方的数块和,如果存在大于0的,则可以加入最大子数组和的运算 if(t>0) { max+=t; t=0; } } System.out.println("最大子数组的和为:" + max); } }