最大连续子数组和

来源:互联网 发布:中投证券交易软件 编辑:程序博客网 时间:2024/05/18 17:27

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

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

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

                    本质上就是穷举所有的子数组,然后求和。此方法的时间复杂度为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类中全部实现,分别对应三个方法,都是比较通用的代码,读者可以很容易转换为其他语言实现。

public class Maxsum {    public static int fun1(int array[]){     //时间复杂度为O(n^3)    int n=array.length;    if(n<=0)return 0;                    //如果是空数组,直接返回0    int maxSum = array[0];               //最小和设为第一个数组元素的值        int currSum = 0;        for (int i = 0; i < n; i++)          //子数组起点        {            for (int j = i; j < n; j++)      //子数组终点            {                for (int k = i; k <= j; k++)   //子数组求和                {                    currSum += array[k];                }                if (currSum > maxSum)         //更新最大和                    maxSum = currSum;                currSum = 0;                 //每次用完清空            }        }        return maxSum;    }        public static int fun2(int array[]){     //时间复杂度为O(n)    int n=array.length;    if(n<=0)return 0;                    //如果是空数组,直接返回0    int currSum = 0;        int maxSum = array[0];               for (int j = 0; j < n; j++)        {            currSum = (array[j] > currSum + array[j]) ? array[j] : currSum + array[j];            maxSum = (maxSum > currSum) ? maxSum : currSum;        }        return maxSum;    }        public static int fun3(int array[]){          //动态规划思想,时间复杂度为O(n)    int n=array.length;    if(n<=0)return 0;                    //如果是空数组,直接返回0    int f[]=new int[n];        f[0]=array[0];        int max=f[0];        for(int i=1;i<f.length;i++)        {if(f[i-1]<=0 ||i==0)f[i]=array[i];        else f[i]=f[i-1]+array[i];        if(max<f[i])max=f[i];        }    return max;    }public static void main(String[] args) {// TODO 自动生成的方法存根        int a[]={1,-2,3,10,-4,7,2,-5};        System.out.print("数组为:");        for(int i=0;i<a.length;i++)        System.out.print(a[i]+",");        System.out.println();        System.out.println("暴力法求解答案为:"+fun1(a));        System.out.println("扫描法求解答案为:"+fun2(a));        System.out.println("动态规划求解答案为:"+fun3(a));}}

输出结果为:

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


0 0
原创粉丝点击