求数组的子数组之和的最大值
问题描述
分析与解法
【解法一】
具体代码如下:
1 package chapter2shuzizhimei.maxsumsubarray; 2 /** 3 * 求数组的子数组之和的最大值 4 * 【解法一】 5 * @author DELL 6 * 7 */ 8 public class MaxSumSubArray1 { 9 //求数组的子数组之和的最大值 10 public static double maxSum(double a[]){ 11 double maxSum = a[0]; 12 int i,j,k,n=a.length; 13 for(i=0;i<n;i++){ 14 for(j=i;j<n;j++){ 15 double sum = 0; 16 for(k=i;k<=j;k++){ 17 sum += a[k]; 18 } 19 if(sum>maxSum) 20 maxSum = sum; 21 } 22 } 23 return maxSum; 24 } 25 public static void main(String[] args) { 26 double a[]={1,-2,3,5,-3,2}; 27 double b[]={0,-2,3,5,-1,2}; 28 double c[]={-9,-2,-3,-5,-3}; 29 System.out.println("求数组的子数组之和的最大值为:"+maxSum(a)); 30 System.out.println("求数组的子数组之和的最大值为:"+maxSum(b)); 31 System.out.println("求数组的子数组之和的最大值为:"+maxSum(c)); 32 33 } 34 35 }
程序运行结果如下:
求数组的子数组之和的最大值为:8.0 求数组的子数组之和的最大值为:9.0 求数组的子数组之和的最大值为:-2.0
代码如下:
1 package chapter2shuzizhimei.maxsumsubarray; 2 /** 3 * 求数组的子数组之和的最大值 4 * 【解法一】优化 5 * @author DELL 6 * 7 */ 8 public class MaxSumSubArray2 { 9 //求数组的子数组之和的最大值 10 public static double maxSum(double a[]){ 11 double maxSum = a[0]; 12 int i,j,k,n=a.length; 13 for(i=0;i<n;i++){ 14 double sum = 0; //优化修改 15 for(j=i;j<n;j++){ 16 sum += a[j]; //优化修改 17 if(sum>maxSum) 18 maxSum = sum; 19 } 20 } 21 return maxSum; 22 } 23 public static void main(String[] args) { 24 double a[]={1,-2,3,5,-3,2}; 25 double b[]={0,-2,3,5,-1,2}; 26 double c[]={-9,-2,-3,-5,-3}; 27 System.out.println("求数组的子数组之和的最大值为:"+maxSum(a)); 28 System.out.println("求数组的子数组之和的最大值为:"+maxSum(b)); 29 System.out.println("求数组的子数组之和的最大值为:"+maxSum(c)); 30 31 } 32 33 }
程序运行结果如下:
求数组的子数组之和的最大值为:8.0 求数组的子数组之和的最大值为:9.0 求数组的子数组之和的最大值为:-2.0
【解法二】
具体代码如下:
1 package chapter2shuzizhimei.maxsumsubarray; 2 /** 3 * 求数组的子数组之和的最大值 4 * 【解法二】递归求解 5 * @author DELL 6 * 7 */ 8 public class MaxSumSubArray3 { 9 //找两个数的最大值 10 public static double max(double a,double b){ 11 return a>b ? a:b; 12 } 13 //求数组的子数组之和的最大值 14 public static double maxSum(double a[],int first, int last){ 15 if(first==last) 16 return a[first]; 17 int n = last-first+1; 18 double LmaxSum = maxSum(a, first, first+n/2-1); //左边的最大值 19 double RmaxSum = maxSum(a, first+n/2, last); //右边的最大值 20 double maxSum = max(LmaxSum,RmaxSum); //总的最大值 21 double maxSuml = a[first+n/2-1]; //横跨两段的左边段的最大值 22 double maxSumr = a[first+n/2]; //横跨两段的右边段的最大值 23 double sum = 0; 24 for(int i=first+n/2-1;i>=first;i--){ 25 sum += a[i]; 26 if(sum>maxSuml) 27 maxSuml = sum; 28 } 29 sum = 0; 30 for(int i=first+n/2;i<=last;i++){ 31 sum += a[i]; 32 if(sum>maxSumr) 33 maxSumr = sum; 34 } 35 maxSum = max(maxSum,maxSuml+maxSumr); 36 return maxSum; 37 } 38 public static void main(String[] args) { 39 double a[]={1,-2,3,5,-3,2}; 40 double b[]={0,-2,3,5,-1,2}; 41 double c[]={-9,-2,-3,-5,-3}; 42 System.out.println("求数组的子数组之和的最大值为:"+maxSum(a,0,a.length-1)); 43 System.out.println("求数组的子数组之和的最大值为:"+maxSum(b,0,b.length-1)); 44 System.out.println("求数组的子数组之和的最大值为:"+maxSum(c,0,c.length-1)); 45 46 } 47 48 }
程序运行结果如下:
求数组的子数组之和的最大值为:8.0 求数组的子数组之和的最大值为:9.0 求数组的子数组之和的最大值为:-2.0
【解法三】
具体代码如下:
1 package chapter2shuzizhimei.maxsumsubarray; 2 /** 3 * 求数组的子数组之和的最大值 4 * 【解法三】动态规划 5 * @author DELL 6 * 7 */ 8 public class MaxSumSubArray4 { 9 //找两个数的最大值 10 public static double max(double a,double b){ 11 return a>b ? a:b; 12 } 13 //求数组的子数组之和的最大值 14 public static double maxSum(double a[]){ 15 int n = a.length; 16 double start[] = new double[n]; //start[i]表示从a[i]包含a[i]开始的最大和 17 double all[] = new double[n]; //all[i]表示从从a[i]到a[n-1]的一段中子数组之和的最大值 18 start[n-1] = a[n-1]; 19 all[n-1] = a[n-1]; 20 for(int i=n-2;i>=0;i--){ 21 start[i] = max(a[i],a[i]+start[i+1]); 22 all[i] = max(start[i],all[i+1]); 23 } 24 return all[0]; 25 } 26 public static void main(String[] args) { 27 double a[]={1,-2,3,5,-3,2}; 28 double b[]={0,-2,3,5,-1,2}; 29 double c[]={-9,-2,-3,-5,-3}; 30 System.out.println("求数组的子数组之和的最大值为:"+maxSum(a)); 31 System.out.println("求数组的子数组之和的最大值为:"+maxSum(b)); 32 System.out.println("求数组的子数组之和的最大值为:"+maxSum(c)); 33 34 } 35 36 }
程序运行结果如下:
求数组的子数组之和的最大值为:8.0 求数组的子数组之和的最大值为:9.0 求数组的子数组之和的最大值为:-2.0
具体代码如下:
1 package chapter2shuzizhimei.maxsumsubarray; 2 /** 3 * 求数组的子数组之和的最大值 4 * 【解法三】动态规划 优化(减少空间复杂度) 5 * @author DELL 6 * 7 */ 8 public class MaxSumSubArray5 { 9 //找两个数的最大值 10 public static double max(double a,double b){ 11 return a>b ? a:b; 12 } 13 //求数组的子数组之和的最大值 14 public static double maxSum(double a[]){ 15 int n = a.length; 16 double start; //start[i]表示从a[i]包含a[i]开始的最大和 17 double all; //all[i]表示从从a[i]到a[n-1]的一段中子数组之和的最大值 18 start = a[n-1]; 19 all = a[n-1]; 20 for(int i=n-2;i>=0;i--){ 21 start = max(a[i],a[i]+start); 22 all = max(start,all); 23 } 24 return all; 25 } 26 public static void main(String[] args) { 27 double a[]={1,-2,3,5,-3,2}; 28 double b[]={0,-2,3,5,-1,2}; 29 double c[]={-9,-2,-3,-5,-3}; 30 System.out.println("求数组的子数组之和的最大值为:"+maxSum(a)); 31 System.out.println("求数组的子数组之和的最大值为:"+maxSum(b)); 32 System.out.println("求数组的子数组之和的最大值为:"+maxSum(c)); 33 34 } 35 36 }
程序运行结果如下:
求数组的子数组之和的最大值为:8.0 求数组的子数组之和的最大值为:9.0 求数组的子数组之和的最大值为:-2.0
改进的算法不仅节省了空间,而且只有寥寥几行,却达到了很高的效率。我们还可以换一个写法:
1 package chapter2shuzizhimei.maxsumsubarray; 2 /** 3 * 求数组的子数组之和的最大值 4 * 【解法三】动态规划 优化(减少空间复杂度) 5 * @author DELL 6 * 7 */ 8 public class MaxSumSubArray6 { 9 //找两个数的最大值 10 public static double max(double a,double b){ 11 return a>b ? a:b; 12 } 13 //求数组的子数组之和的最大值 14 public static double maxSum(double a[]){ 15 int n = a.length; 16 double start; //start[i]表示从a[i]包含a[i]开始的最大和 17 double all; //all[i]表示从从a[i]到a[n-1]的一段中子数组之和的最大值 18 start = a[n-1]; 19 all = a[n-1]; 20 for(int i=n-2;i>=0;i--){ 21 if(start<0) 22 start = 0; 23 start = a[i]+start; 24 if(start>all) 25 all = start; 26 } 27 return all; 28 } 29 public static void main(String[] args) { 30 double a[]={1,-2,3,5,-3,2}; 31 double b[]={0,-2,3,5,-1,2}; 32 double c[]={-9,-2,-3,-5,-3}; 33 System.out.println("求数组的子数组之和的最大值为:"+maxSum(a)); 34 System.out.println("求数组的子数组之和的最大值为:"+maxSum(b)); 35 System.out.println("求数组的子数组之和的最大值为:"+maxSum(c)); 36 37 } 38 39 }
程序运行结果如下:
求数组的子数组之和的最大值为:8.0 求数组的子数组之和的最大值为:9.0 求数组的子数组之和的最大值为:-2.0
扩展问题
(注:上面的i>j应改为i<=j)
问题1 代码如下:
1 package chapter2shuzizhimei.maxsumsubarray; 2 /** 3 * 求数组的子数组之和的最大值 4 * 扩展问题1 5 * @author DELL 6 * 7 */ 8 public class MaxSumSubArray7 { 9 //找两个数的最大值 10 public static double max(double a,double b){ 11 return a>b ? a:b; 12 } 13 //求数组的子数组之和的最大值,循环数组 14 public static double maxSum(double a[]){ 15 int n = a.length; 16 double start; //start[i]表示从a[i]包含a[i]开始的最大和 17 double all; //all[i]表示从从a[i]到a[n-1]的一段中子数组之和的最大值 18 start = a[n-1]; 19 all = a[n-1]; 20 for(int i=n-2;i>=0;i--){ 21 if(start<0) 22 start = 0; 23 start = a[i]+start; 24 if(start>all) 25 all = start; 26 } 27 double max1=a[n-1],max2=a[0],sum=0; 28 int i = n-1,j = 0; 29 //寻找以a[n-1]结尾的最大值 30 for(int k=n-1;k>=0;k--){ 31 sum += a[k]; 32 if(sum>max1){ 33 max1 = sum; 34 i = k; 35 } 36 } 37 sum = 0; 38 //寻找以a[0]开始的最大值 39 for(int k=0;k<n;k++){ 40 sum += a[k]; 41 if(sum>max1){ 42 max2 = sum; 43 j = k; 44 } 45 } 46 double max; 47 if(i<=j){ 48 max = sum; 49 }else{ 50 max = max1 + max2; 51 } 52 return max(all,max); 53 } 54 public static void main(String[] args) { 55 double a[]={1,-2,3,5,-3,2}; 56 double b[]={0,-2,3,5,-1,2}; 57 double c[]={-9,-2,-3,-5,-3}; 58 double d[]={4,5,-9,-8,1,2,3}; 59 System.out.println("求数组的子数组之和的最大值为:"+maxSum(a)); 60 System.out.println("求数组的子数组之和的最大值为:"+maxSum(b)); 61 System.out.println("求数组的子数组之和的最大值为:"+maxSum(c)); 62 System.out.println("求数组的子数组之和的最大值为:"+maxSum(d)); 63 64 } 65 66 }
程序运行结果如下:
求数组的子数组之和的最大值为:8.0 求数组的子数组之和的最大值为:9.0 求数组的子数组之和的最大值为:-2.0 求数组的子数组之和的最大值为:15.0
问题2 还能保持O(N)的时间复杂度
具体代码如下:
1 package chapter2shuzizhimei.maxsumsubarray; 2 /** 3 * 求数组的子数组之和的最大值 4 * 扩展问题1 5 * @author DELL 6 * 7 */ 8 public class MaxSumSubArray8 { 9 //找两个数的最大值 10 public static double max(double a,double b){ 11 return a>b ? a:b; 12 } 13 //求数组的子数组之和的最大值,循环数组 14 public static double maxSum(double a[]){ 15 int first,last; //记录最大数组的位置 16 int n = a.length; 17 double start; //start[i]表示从a[i]包含a[i]开始的最大和 18 double all; //all[i]表示从从a[i]到a[n-1]的一段中子数组之和的最大值 19 start = a[n-1]; 20 first = n-1; 21 last = n-1; 22 all = a[n-1]; 23 for(int i=n-2;i>=0;i--){ 24 if(start<0){ 25 start = 0; 26 last = i; 27 } 28 start = a[i]+start; 29 if(start>all){ 30 all = start; 31 first = i; 32 } 33 } 34 if(first>last) 35 last = first; 36 double max1=a[n-1],max2=a[0],sum=0; 37 int i = n-1,j = 0; 38 //寻找以a[n-1]结尾的最大值 39 for(int k=n-1;k>=0;k--){ 40 sum += a[k]; 41 if(sum>max1){ 42 max1 = sum; 43 i = k; 44 } 45 } 46 sum = 0; 47 //寻找以a[0]开始的最大值 48 for(int k=0;k<n;k++){ 49 sum += a[k]; 50 if(sum>max1){ 51 max2 = sum; 52 j = k; 53 } 54 } 55 double max; 56 if(i<=j){ 57 max = sum; 58 }else{ 59 max = max1 + max2; 60 } 61 if(max>all){ 62 if(i<=j) 63 System.out.println("最大子数组的位置为整个数组!"); 64 else 65 System.out.println("最大子数组的位置为(数组下标):"+i+" -> "+j); 66 }else{ 67 System.out.println("最大子数组的位置为(数组下标):"+first+" -> "+last); 68 } 69 return max(all,max); 70 } 71 public static void main(String[] args) { 72 double a[]={1,-2,3,5,-3,2}; 73 double b[]={0,-2,3,5,-1,2}; 74 double c[]={-9,-2,-3,-5,-3}; 75 double d[]={4,5,-9,-8,1,2,3}; 76 double e[]={4,5,1,6,1,2,3}; 77 System.out.println("求数组的子数组之和的最大值为:"+maxSum(a)); 78 System.out.println("求数组的子数组之和的最大值为:"+maxSum(b)); 79 System.out.println("求数组的子数组之和的最大值为:"+maxSum(c)); 80 System.out.println("求数组的子数组之和的最大值为:"+maxSum(d)); 81 System.out.println("求数组的子数组之和的最大值为:"+maxSum(e)); 82 83 } 84 85 }
程序运行结果如下:
最大子数组的位置为(数组下标):2 -> 3 求数组的子数组之和的最大值为:8.0 最大子数组的位置为(数组下标):2 -> 5 求数组的子数组之和的最大值为:9.0 最大子数组的位置为(数组下标):1 -> 1 求数组的子数组之和的最大值为:-2.0 最大子数组的位置为(数组下标):4 -> 1 求数组的子数组之和的最大值为:15.0 最大子数组的位置为(数组下标):0 -> 6 求数组的子数组之和的最大值为:22.0
时间: 2024-10-06 15:52:54