zoukankan      html  css  js  c++  java
  • 连续最大字段和问题

    最大子段和问题描述

    给定由 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);
        }
    

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

  • 相关阅读:
    一行代码搞定Dubbo接口调用
    测试周期内测试进度报告规范
    jq 一个强悍的json格式化查看工具
    浅析Docker容器的应用场景
    HDU 4432 Sum of divisors (水题,进制转换)
    HDU 4431 Mahjong (DFS,暴力枚举,剪枝)
    CodeForces 589B Layer Cake (暴力)
    CodeForces 589J Cleaner Robot (DFS,或BFS)
    CodeForces 589I Lottery (暴力,水题)
    CodeForces 589D Boulevard (数学,相遇)
  • 原文地址:https://www.cnblogs.com/blogtech/p/11116524.html
Copyright © 2011-2022 走看看