第2章 数字之魅——求数组的子数组之和的最大值

求数组的子数组之和的最大值

问题描述

分析与解法

【解法一】

具体代码如下:

 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

第2章 数字之魅——求数组的子数组之和的最大值的相关文章

编程之美之2.14 求数组的子数组之和的最大值

[题目] 一个有N个整数元素的一维数组(A[0],A[1],A[2],...A[n-1]),这个数组中当然有很多子数组,那么子数组之和的最大值是多少? 该子数组是连续的. 我们先来明确一下题意: (1)子数组意味着是连续的. (2)题目只需要求和,并不需要返回子数组的具体位置. (3)数组的元素是整数,所以数组可能包含正整数,负整数或者零. 举几个例子: 数组:[1,-2,3,5,-3,2]返回8 数组:[0,-2,3,5,-1,2]返回9 数组:[-9,-2,-3,-5,-3]返回8 [解法一

编程之美2.14 求数组的子数组之和的最大值

问题描述: 一个有N个整数元素的一维数组(A[0], A[1], A[2],...,A[n-1]),这个数组当然有很多子数组,那么子数组之和的最大值是什么呢? 解法: 1. 暴力解法-------O(N^3) 2. 改进版暴力解法-------O(N^2) *3. 分治算法-------O(NlogN)(暂时未去实现) 4. 数组间关系法-------O(N) 具体思路和代码: 1.暴力解法 思路:Sum[i,...,j]为数组第i个元素到第j个元素的和,遍历所有可能的Sum[i,...,j].

求数组的子数组之和的最大值?

自己写的代码考虑未周全,引入了额外的空间复杂度: //求数组的子数组之和的最大值 #include <iostream> #define N 12 using namespace std; int main() { //int a[]={-5,2,3,-3,-2,3,1,-5}; //int a[]={-5,2,0,3,-2,3,4,5}; int a[]={1,-2,3,10,-4,7,2,-5}; int flag,max,i,j=0; int sum[N]={0}; //(1)记录子数组

[编程之美] 2.14 求数组的子数组之和的最大值

问题描述:给定一个包含N个整数的数组,求数组的子数组之和的最大值. 这是递归和贪心策略的一个经典问题.现在,对这个问题进行一下总结. 1 明确题意 题目中的子数组要求是连续的,也就是数组中的某个连续部分. 如果数组中都是正整数,直接相加就行.因此,主要是要考虑负数的情况. 2 直接求所有的子数组和 最简单且容易理解的解法是求出所有的子数组和,然后保存最大的和. int MaxSum(int *A, int n) { int maximum = -INF; int sum = 0; int i =

2.14 求数组的子数组之和的最大值

题目:给定一个一维数组,求这个数组的子数组之和的最大值. 最佳方法:动态规划! 一. 可以将一个大问题(N个元素数组)转化为一个较小的问题(N-1个元素数组).. 假设已经知道(A[1],...A[n-1])中最大的子数组的和为:All[1] 并且已经知道(A[1],...A[n-1])中包括A[1]的子数组的最大和为start[1] 所以最终的解All[0] = max(A[0], A[0]+start[1], All[1]) 所以通过DP来求解! 代码如下: #include <iostre

编程之美 2.14求数组的子数组之和的最大值

对于一个有N个元素的数组,a[0]~a[n-1],求子数组最大值. 如:数组A[] = [−2, 1, −3, 4, −1, 2, 1, −5, 4],则连续的子序列[4,−1,2,1]有最大的和6. 方法一:暴力 循环遍历,输出所有,判断最大的和 1 #include"iostream" 2 #define MAX 1001 3 using namespace std; 4 5 int main(){ 6 int n, a[MAX], sum , maxsum ; 7 8 cin &

【编程之美】求数组的子数组之和的最大值

一个有N个整数元素的一维数组A[0],A[1],......,A[n-1],这个数组当然有很多子数组,那么子数组的最大值是什么呢? 分析与解法 我们先明确题意: 1. 题目说的子数组,是连续的: 2. 题目只需要求和,并不需要返回子数组的具体位置: 3. 数组中的元素是整数,所以数组可能包含有正整数.零.负整数: 4. 子数组不为空. 解法一:枚举 最简单的办法就是枚举所有的i和j,计算sum[i..j] = A[i]+A[i+1]+...+A[j],遍历所有可能的sum[i..j],找到最大值

C#中求数组的子数组之和的最大值

<编程之美>183页,问题2.14——求子数组的字数组之和的最大值.(整数数组) 我开始以为可以从数组中随意抽调元素组成子数组,于是就有了一种想法,把最大的元素抽出来,判断是大于0还是小于等于0,如果大于0就对除了这个最大值外剩下的数组部分进行递归: using System; using System.Collections.Generic; using System.Linq; namespace MaxSumSubArray { class Program { static void M

求数组的子数组之和的最大值及扩展问题2

这是一道来自<编程之美>2.14节的题目. 这篇博文把思路写了一下.在此我要特别说明的是方法二和方法三的自己写的东西. 我把方法二的分治法用C++实现了一下,代码如下: int MAX(int a,int b,int c) { int t=a>b?a:b; return t>c?t:c; } int Array(int a[],int i,int j) { if (i<j) { int q=(i+j)/2,sum1=0,sum2=0,k,Max1=-0x7fffffff,Ma