求最大子段和问题

求最大子段和的问题是比较经典的算法,可以由简单的算法到复杂的算法逐步递进。


问题描述:

给定序列a [1],a [2],a [3] …… a [n],您的工作是计算子序列的最大和。
例如,给定(6,-1,5, 4,-7),此序列中的最大和为6 +(-1)+ 5 + 4 = 14。
给定(0,6,-1,1,-6,7,-5),最大和为7。


算法一:穷举法(枚举法)

把所有的情况都算出来,取出最大值,这种算法的时间复杂度为O(n^3),i从数组头部到尾部,j从i到数组尾部,k从i到j。

public int MaxSum(int[] array) {
        int currentSum = 0;
        int sum = 0;
        for (int i = 0; i < array.length; i++) {
            for (int j = i; j < array.length; j++) {
                currentSum = 0;
                for (int k = i; k <= j; k++) {
                    currentSum = currentSum + array[k];
                }
                if (currentSum > sum) {
                    sum = currentSum;
                }
            }
        }
        return sum;
    }

如果看不懂上面的算法,可以在纸上写出来,用了三层循环遍历计算所有的结果,在上述代码中其实有好多的计算是重复的,例如:当i=0,j=3时要计算a[0]+a[1]+a[2]+a[3],当j=4时,要计算a[0]+a[1]+a[2]+a[3]+a[4],显然这个计算有一部分是多余的。第一层循环从0到array的长度-1,第二、三层循环主要负责计算子段的和,把每次计算的子段和和存到currentSum变量中,与sum进行比较(sum存储的是最终的最大子段和),如果大则进行交换。通过分析上面的代码有大量的重复计算,效率不高。

算法二:依然是枚举法

分析算法一发现有大量的重复计算,避免这些重复计算可以提高很多的效率,我们发现算法一中的一个循环可以去掉。

public int MaxSum1(int[] array) {
        int currentSum = 0;
        int sum = 0;
        for (int i = 0; i < array.length; i++) {
            currentSum = 0;
            for (int j = i; j < array.length; j++) {
                currentSum += array[j];
                if (currentSum > sum) {
                    sum = currentSum;
                }
            }
        }
        return sum;
    }

虽然算法二较算法一减少了一层循环,时间复杂度可以减少到O(n^2)。不需要k,在找到j的时候就将子段和记录下来。但是依然存在重复的计算,还不是最优的。

算法三:动态规划

目标减少重复计算的次数,尽可能避免重复的计算过程,依然是减少循环

public int MaxSum2(int[] array) {
        int currentSum = 0;
        int sum = 0;
        for (int i = 0; i < array.length; i++) {
            currentSum += array[i];
            if (currentSum > sum) {
                sum = currentSum;
            }
            if (currentSum < 0) {
                currentSum = 0;
            }
        }
        return sum;
    }

上面的算法过程是循环遍历整个数组,接着计算每个子段的和,判断这个子段和,第一次循环如果大于0则赋值给sum,小于0不计算当前元素,接着第二次循环加上上次循环中计算出的子段和……
下面是动态规划算法另一种实现形式:

public int MaxSum3(int[] array) {
        int num = array.length;
        int sum = 0;
        int y = 0;
        for (int i = 0; i < num; i++) {
            if (y > 0) {
                y += array[i];
            } else {
                y = array[i];
            }
            if (y > sum) {
                sum = y;
            }
        }
        return sum;
    }

由于只有一层循环,时间复杂度降为O(n)

posted @ 2018-03-12 20:51  In_new  阅读(280)  评论(0编辑  收藏  举报