• 编程之美:求数组的子数组之和的最大值


    1.问题描述

    一个有N个整数元素的一维数组( A[0], A[1], ... , A[n-2], A[n-1]),子数组之和的最大值是什么?(要求子数组的元素是连续的)

    例子:有数组( -2, 5, 3, -6, 4, -8, 6),则其子数组之和的最大值为8,其对应的数组为(5,3)

    2.分析与解法

    解法一:采用直接法,记Sum[i...j],为数组A中从第i到第j之间所有数之和,算出所有Sum,取其最大,代码如下,时间复杂度O(N2):

    int maxSum1(int *A, int n)
    {
        int max = -1;
        int i, j, sum;
        
        for(i = 0; i < n; i++)
        {
              sum = 0;
              for(j = i; j < n; j++)
              {
                    sum += A[j];
                    if(sum > max )
                           max = sum;
              }
        }
        
        return max;
    }

    解法二:使用分治法,数组(A[0],A[1],...A(n-1)分为长度相等的两段数组(A[0],...,A[n/2-1])以及(A[n/2],...,A[n-1]),分别求出这两段数组各自的最大子段和,则原数组(A[0],A[1],...A(n-1)的最大子段和分为3种情况

    1).(A[0],A[1],...A(n-1)的最大子段和与(A[0],...,A[n/2-1])的相同

    2).(A[0],A[1],...A(n-1)的最大子段和与(A[n/2],...,A[n-1])的相同

    3).(A[0],A[1],...A(n-1)的最大子段和跨过(A[0],...,A[n/2-1])与(A[n/2],...,A[n-1])-

    1)和2)可以根据递归可得,3)只要计算出以A[n/2-1]为结尾的一段数组最大和s1=Sum1[i...n/2-1]和A[n/2]为开头一段数组最大和s2=Sum2[n/2...j],最后s=s1+s2.

    这个算法满足分值算法递归,总的时间复杂度O(N*log2N)

    解法三:假设我们已经知道(A[k].....A[n-1])最大的一段数组和为All[k],并且已经计算出在(A[k].....A[n-1])中包含A[k]的最大的一段数组和为Start[k],那么可以推断出All[k-1]=max{A[k-1],A[k-1]+Start[k],All[k]},利用动态规划思想以及这样的递推公式,从后往前计算,代码如下,时间复杂度O(N):

    int max(int x, int y)
    {
        return (x > y) ? x : y;
    }
    
    int maxSum2(int *A, int n)
    {
        int i;
        int All[n], Start[n];
        
        All[n-1] = A[n-1];
        Start[n-1] = A[n-1];
        
        for(i = n-2; i >= 0; i--)
        {
              Start[i] = max(A[i], A[i]+Start[i+1]);
              All[i] = max(All[i+1], Start[i]);
        }
        
        return All[0];    
    }

     
    对以上代码进行简化,因为最后所求到的变量只有Start[0]和All[0],这样可以反复用nStart和nAll,省略掉其他的变量,代码如下:

    int max(int x, int y)
    {
        return (x > y) ? x : y;
    }
    
    int maxSum2_v(int *A, int n)
    {
        int i;
        int nAll, nStart;
        
        nAll = A[n-1];
        nStart = A[n-1];
        
        for(i = n-2; i >= 0; i--)
        {
              nStart = max(A[i], A[i]+nStart);
              nAll = max(nAll, nStart);
        }
        
        return nAll;    
    }

    注:以上的计算顺序也可以从前往后,即:All[k+1]=max{A[k+1],A[k+1]+Start[k],All[k]}.

  • 相关阅读:
    ssrf简介
    Mysql 命令 load data infile
    基于约束的SQL注入笔记
    ms17-010
    thinkphp5.0&5.1命令执行 和 thinkphp3.2.3sql注入
    抓取分析菜刀流量
    lamp环境的搭建
    php伪协议
    LeetCode-336 Palindrome Pairs
    LeetCode-335 Self Crossing
  • 原文地址:https://www.cnblogs.com/biyeymyhjob/p/2643609.html
Copyright © 2020-2023  润新知