zoukankan      html  css  js  c++  java
  • 第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
  • 相关阅读:
    STL中的map
    HDU 4027 Can you answer these queries?
    HDU 2199 Can you solve this equation?
    USACO section1.2 Name That Number 命名那个数字
    HDU 3790 最短路径问题 (双重权值)
    [笔记]CiscoPT配置RIP
    [笔记]Cisco PT VLANTrunk配置
    iptables感悟Ubuntu
    CentOS网络配置
    Discuz X2 数据库备份功能分析
  • 原文地址:https://www.cnblogs.com/gaopeng527/p/4628396.html
Copyright © 2011-2022 走看看