zoukankan      html  css  js  c++  java
  • 求数组的子数组之和的最大值

    明确题意:

    1. 子数组是连续的
    2. 只需要求和,不需要返回子数组的具体位置
    3. 元素是整数,数组可能包含正整数、零、负整数

    举例子:

    数组 [1, -2, 3, 5, -3, 2] 应返回: 8

    明确题意


      起初我想的是即使是循环,也不能解决这个问题,比如以上例子中元素3,5组成“最大”子数组。更何况如果3和5距离很远。当然后者加剧了题目的复杂度。

    所以,第一步,明确“题”意是求解很重要的一环。

    示例代码1:

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

    但是通过以上O(n^2)复杂度的算法,确实得出题目的解。

    实际上这里面是隐含着我所考虑的情况,而且是全部。所要求的是一个连续的子数组的和。那么所有的情况可以分类:

    针对1个元素,(a)组成的数组,那么肯定只能是它本身;
    针对2个元素,(a,b)组成的数组,除了第一种情况之外,那么就是唯一的一个组合,(第一个元素,第二个元素),即(a,b)
    针对3个元素,(a,b,c)组成的数组,也可以罗列出来,如:a或b或c,组合有(a,b) 或 (b,c)(其中ac不满足连续的要求)
    针对4个元素,(以此类推)

     以上是一个类似小学数学教育当中经常用到的不完全归纳法,通过这种分析,可以得出一种结果,就是,最大子数组的可以按一种标准分类,那就是子数组元素的个数。再加上一个额外的限制条件连续,就可以使用两个循环来解决问题。对于n个元素组成的数组:

    123 ,... ,n)

    设连续的子数组情况有m种(数学不好,凑合着表示):

    m = cn1 + (cn2 - 不连续的) + (cn3 - 不连续的) + ... +  (cnn-不连续的)

    回过头来再看 示例代码1,内外两层循环上来看,的确是覆盖了以上所有的组合情况。

    以数组下表来表示:

    maximum来保存最大的子数组和,sum保存某一种子数组的元素组合情况。以下分别用数组元素下标来表示元素的值:
    
    当i=0的时候,sum分别来表示 00+1, (0+1)+2, (01+2)+ 3  , ... , (0+1+2+3+ ... + n-1) + n
    
    当i=1的时候,sum分别来表示 11+2, (1+2)+ 3  , ... , (1+2+3+ ... + n-1) + n
    ... 当i=n-1的时候,sum分别来表示 n-
    1, n-1 + n 当i=n的时候,sum分别来表示 n

    以上的组合均是连续的。

    对于文章开头的例子,最大子数组(3,5)中元素在原来数组中的下表分别是(2,3),即当n=5,i=2,j=3的时候便得到了最大值8

    在合适的地方打上适当的输出语句用以观察整个运算情况:

    i    j    sum    maximum
    0    0    1    1
    0    1    -1    1
    0    2    2    2
    0    3    7    7
    0    4    4    7
    0    5    6    7
    
    1    1    -2    7
    1    2    1    7
    1    3    6    7
    1    4    3    7
    1    5    5    7
    
    2    2    3    7
    2    3    8    8
    2    4    5    8
    2    5    7    8
    
    3    3    5    8
    3    4    2    8
    3    5    4    8
    
    4    4    -3    8
    4    5    -1    8
    
    5    5    2    8

    分治


     每个问题都可以分解成为两个问题规模减半的子问题,再加上一次遍历算法。

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

    同样地,在合适的地方打印出结果:

    i    A[i]    nStart    nAll
    4    -3       -1        2
    3    5        5        5
    2    3        8        8
    1    -2       6        8
    0    1        7        8

     动态规划,分治待看。

  • 相关阅读:
    Ubuntu Git GUI工具GitKraken安装
    轻松理解String.intern()
    Ubuntu MySQL安装
    稳定与不稳定的人生(转自知乎)
    【推荐】我们这一代人的困惑
    没关系,因为你是好人呀
    论文--Topic-Sensitive PageRank
    论文笔记-Mining latent relations in peer-production environments
    Open Source Book For ML
    LeetCode-Populating Next Right Pointers in Each Node
  • 原文地址:https://www.cnblogs.com/dotdog/p/4526908.html
Copyright © 2011-2022 走看看