连续最大字段和问题

最大子段和问题描述

给定由 n 个整数(可能为负整数)组成的序列a1,a2,a3...an,求该数列中连续子段和最大!

    例如:当(a1,a2,a3,a4,a5)=(-2,11,-4,13,-5,-2)时,最大字段和为 20 (11 + (-4) + 13);

       以下例子都是以int data[6] = {-2,11,-4,13,-5,-2};    int n = 6;

 初始化数组: 

    //初始化数组
    private static Integer[] array = {-2, 11, -4, 13, -5, -2};

算法一:对所有满足0<=i<=j<=n的(i,j)整数对进行迭代,对每个整数对,程序都要计算array[i...j]的总和,并检验该总和是否大于迄今为止的最大总和

这段代码简洁明了,便于理解,但是程序执行的速度很慢,时间复杂度为O(n^3)

  

  /**
     * 时间复杂度为 O(n^3)
     */
    public static Integer maxSum1() {
        int maxSum = 0;             //存储最大子段和
        int tempSum;                //临时存储最大子段和
        for (int i = 0; i < array.length - 1; i++) {
            for (int j = i; j < array.length; j++) {
                tempSum = 0;
                for (int k = i; k <= j; k++) {
                    tempSum += array[k];
                    if (tempSum > maxSum) {
                        maxSum = tempSum;
                    }
                }
            }
        }
        return maxSum;
    }

  

算法二:对于算法一有一个明显的缺点,大量的计算重复。大家可以注意到:

这段代码简洁明了,便于理解,相比算法一程序执行的速度较快,时间复杂度为O(n^2)

  注意:array[i...j]的总和与前面计算出的总和(array[i...j-1])密切相关,只需要在其基础上累加即可,无需大量重复计算!

    /**
     * 时间复杂度为 O(n^2)
     */
    public static Integer maxSum2() {
        int maxSum = 0;             //存储最大子段和
        int tempSum;                //临时存储最大子段和
        for (int i = 0; i < array.length - 1; i++) {
            tempSum = 0;
            for (int j = i; j < array.length; j++) {
                tempSum += array[j];
                if (tempSum > maxSum) {
                    maxSum = tempSum;
                }
            }
        }
        return maxSum;
    }

  

算法三:可以采用分治算法求解,采用二分法进行二分,然后进行递归求解,分别求出左边连续子段和最大值,右边连续子段和最大值,以及左边和右边连续子段和最大值之和,三者进行比较,从中选择一个最大值进行返回!(这个值即就是当前划分的小区间中最大值)

  注意:这段代码不太便于理解,但是程序相对于算法二执行的速度快,时间复杂度为O(n*logn)

  

  /**
     * 采用分治算法
     * 时间复杂度为 O(n*logN)
     */
    public static Integer maxSum3(int left, int right) {
        int maxSum = 0;
        if (left == right) {    //递归结束条件
            if (array[left] > 0) {
                maxSum = array[left];
            } else {
                maxSum = 0;
            }
            return maxSum;
        }

        int mid = (left + right) / 2;
        int leftMaxSum = maxSum3(left, mid);             //递归求解左部分最大值
        int rightMaxSum = maxSum3(mid + 1, right);  //递归求解右部分最大值

        //求解左边最大值和右边最大值之和
        int leftMax = 0;        //记录左边最大值
        int leftMaxTemp = 0;    //记录左边最大值的临时变量
        for (int i = mid; i >= left; i--) {
            leftMaxTemp += array[i];
            if (leftMaxTemp > leftMax) {
                leftMax = leftMaxTemp;   //左边最大值放在 leftMax
            }
        }
        int rightMax = 0;
        int rightMaxTemp = 0;
        for (int j = mid + 1; j <= right; j++) {
            rightMaxTemp += array[j];
            if (rightMaxTemp > rightMax) {
                rightMax = rightMaxTemp;  //右边最大值放在 rightMax
            }
        }
        maxSum = leftMax + rightMax;//(左边最大值和右边最大值之和)计算第 3 种情况的最大子段和
        //比较(左边最大值)和(右边最大值)以及(两边最大值之和)进行比较,从中选择一个最大值返回
        if (maxSum < leftMaxSum) {
            maxSum = leftMaxSum;
        }
        if (maxSum < rightMaxSum) {
            maxSum = rightMaxSum;
        }
        return maxSum;
    }

  

算法四:使用动态规划来求解 ,由data[]数组我们易知,当maxSumTemp > 0时,maxSumTemp = data[i] + maxSumTemp (越加越大),否则maxSumTemp = data[i](不然越加越小)

  这段代码便于理解,但是程序相对于算法三执行的速度最快,时间复杂度为O(n)

  

    /**
     * 时间复杂度为 O(n)
     */
    public static Integer maxSum4() {
        int maxSum = array[0];
        int maxSumTemp = array[0];  //初始化

        for (int i = 1; i < array.length; i++) {
            if (maxSumTemp > 0) {           //最大值临时变量只有大于零,才可能越加越大
                maxSumTemp += array[i];
            } else {                        //最大值临时变量只有小于零,直接等于data[i],否则越加越小
                maxSumTemp = array[i];
            }
            if (maxSumTemp > maxSum) {      //判断赋值
                maxSum = maxSumTemp;
            }
        }
        return maxSum;
    }

  

测试代码:

 public static void main(String[] args) {
//        Integer maxSum = maxSum1();
//        Integer maxSum = maxSum2();
//        Integer maxSum = maxSum3(0, array.length - 1);
        Integer maxSum = maxSum4();
        System.out.println("maxSum = " + maxSum);
    }

  每天进步一点点,日记月累就会变成大牛!

posted @ 2019-07-01 20:23  菜鸟的奋斗之路  阅读(1619)  评论(0编辑  收藏  举报