最大连续子数组和

问题描述:输入一个整形数组,数组里有正数也有负数。数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和,求所有子数组的和的最大值。

分析:这个问题存在多种解法,各个解法的时间复杂度不一样,这里我列举三种解法。

         解法一:暴力法,可以采用三重循环实现,第一重循环,记作子数组的开始数,第二种循环记作子数组的结尾数,第三重循环计算开始到结尾的和,并和目前最大和进行比较,更新最大和。

                    本质上就是穷举所有的子数组,然后求和。此方法的时间复杂度为O(n^3)。

                    对应下面代码的fun1()方法。

         解法二:对解法一进行优化,当我们求出当前子数组和和时,对于下一个数,如果将其放入子数组中,总和变大了,则直接将该数加入子数组中,否则将这个数作为新的子数组的开始数,依次类推。

                    这种方法的时间复杂度为O(n).

                    对应下面代码的fun2()方法。

         解法三:利用动态规划求解,关于什么是动态规划,这里不再解释,读者可以查阅其他相关资料。

                    我们可以设计一个函数,比如为f(i)表示以第个数字结尾的子数组的最大和,那么我们只要求出f(i)的最大值即可。可以列出以下公式:

                    当 i=0  或者f(i-1)<=0           f(i)=array[i]

                    当 i<>0并且 f(i-1)>0            f(i)=f(i-1)+array[i]

                   再解释下这个公式:当以第i-1个数字结尾的子数组中所有的数字的和小于等于0时,无论第i个数是什么,将他累加到子数组中,得到的结果肯定比他本身小。这时直接将这个数赋值给f(i)即可。

                                            如果以第i-1个数字结尾的子数组中所有的数字的和大于0时,与第i个数累加就得到了以第i个数结尾的子数组中所有数字的和。

                   这种方法的时间复杂度为O(n).

                   对应下面代码的fun3()方法。

          我将三种解法在一个Java类中全部实现,分别对应三个方法,都是比较通用的代码,读者可以很容易转换为其他语言实现。

 1 public class Maxsum {
 2     public static int fun1(int array[]){     //时间复杂度为O(n^3)
 3         int n=array.length;
 4         if(n<=0)return 0;                    //如果是空数组,直接返回0
 5         int maxSum = array[0];               //最小和设为第一个数组元素的值
 6         int currSum = 0;
 7         for (int i = 0; i < n; i++)          //子数组起点
 8         {
 9             for (int j = i; j < n; j++)      //子数组终点
10             {
11                 for (int k = i; k <= j; k++)   //子数组求和
12                 {
13                     currSum += array[k];
14                 }
15                 if (currSum > maxSum)         //更新最大和
16                     maxSum = currSum;
17                 currSum = 0;                 //每次用完清空
18             }
19         }
20         return maxSum;
21     }
22     
23     public static int fun2(int array[]){     //时间复杂度为O(n)
24         int n=array.length;
25         if(n<=0)return 0;                    //如果是空数组,直接返回0
26         int currSum = 0;
27         int maxSum = array[0];       
28         for (int j = 0; j < n; j++)
29         {
30             currSum = (array[j] > currSum + array[j]) ? array[j] : currSum + array[j];
31             maxSum = (maxSum > currSum) ? maxSum : currSum;
32         }
33         return maxSum;
34     }
35     
36     public static int fun3(int array[]){          //动态规划思想,时间复杂度为O(n)
37         int n=array.length;
38         if(n<=0)return 0;                    //如果是空数组,直接返回0
39         int f[]=new int[n];
40         f[0]=array[0];
41         int max=f[0];
42         for(int i=1;i<f.length;i++)
43             {if(f[i-1]<=0 ||i==0)f[i]=array[i];
44             else f[i]=f[i-1]+array[i];
45             if(max<f[i])max=f[i];
46             }
47         return max;
48     }
49 
50     public static void main(String[] args) {
51         // TODO 自动生成的方法存根
52         int a[]={1,-2,3,10,-4,7,2,-5};
53         System.out.print("数组为:");
54         for(int i=0;i<a.length;i++)
55             System.out.print(a[i]+",");
56         System.out.println();
57         System.out.println("暴力法求解答案为:"+fun1(a));
58         System.out.println("扫描法求解答案为:"+fun2(a));
59         System.out.println("动态规划求解答案为:"+fun3(a));
60     }
61 
62 }
View Code

输出结果为:

数组为:1,-2,3,10,-4,7,2,-5,
暴力法求解答案为:18
扫描法求解答案为:18
动态规划求解答案为:18

原文地址:https://www.cnblogs.com/guozhenqiang/p/5431122.html