四种方法解决最大连续子序列和问题

什么是最大连续子序列和问题?

问题描述:给定一个序列(整数或浮点数),求出其中连续的子序列和最大的那一个。

例:序列{-10 1 2 3 4 -5 -23 3 7 -21},其最大的连续子序列为{1 2 3 4}或{3 7},最大和为10.

方法一:暴力求解

最最普通的方法,效率十分低,一般不会用到,这里简单介绍。直接两个for循环枚举子序列的首尾,再来一个for循环计算首尾之间的序列和,计算所有的序列和,找到最大值。

时间复杂度:O(n^3)

效率贼低,千万不要用!(所就不贴代码了)

 

方法二:预处理暴力求解

第一种方法为什么这么慢,原因之一是每次都要计算首尾之间的序列和。基于这个考虑,我们可以对数据进行预先处理:读入数据时使用一个数组SUM[i]来记录前i项数据之和。用这种方法,只需要两个for循环枚举子序列的首尾,利用SUM数组计算子序列和,找到最大值。

时间复杂度:O(n^2)

还是很糟糕,建议不要用。(所以也不贴代码qwq)

 

方法三:分治法求解

把序列分成左右两部分,一般对半分,数量不等也没关系。最大子序列和的位置存在三种情况:1、完全在左半部分;2、完全在右半部分;3、跨越左右两部分。分别求出左半部分的最大子序列和、右半部分的最大子序列和、以及跨越左右两部分的最大子序列和,三者中的最大者就是要求的。

如何求三部分的最大子序列和呢?

左半部分的最大子序列和,可把左半部分作为新的输入序列通过该算法递归求出。右半部分的最大子序列和同理。

接下来就是求解跨越左右两部分的最大子序列和,也就是求出包含左半部分中最右边元素的子序列的最大和,和包含右半部分中最左边元素的子序列的最大和,将两者相加即为跨越左右两个部分的最大子序列和。具体见如下代码:

//分治算法 
int a[999999];

int MAxSubSum(int left,int right)
{
    int sum=0;
    if(left==right)//基本情况:只有一个元素 
        sum=a[left]>0?a[left]:0;
    else
    {
        int center=(left+right)/2;
        int leftsum=MaxSubSum(left,center);//左半部分 
        int rightsum=MAxSubSum(center+1,right);//右半部分 
        
        //求包含左半部分最右元素的最大和 
        int s1=0;
        int lefts=0;
        for(int i=center;i>=left;i--)
        {
            lefts+=a[i];
            if(lefts>s1) s1=lefts;
        }
        
        //求包含右半部分最左元素的最大和 
        int s2=0;
        int rights=0;
        for(int i=center+;i<=right;i++)
        {
            rights+=a[i];
            if(rights>s2) s2=rights;
        }
        
        //取三者最大值 
        sum=s1+s2;
        if(sum<leftsum) sum=leftsum;
        if(sum<rightsum) sum=rightsum;
    }
    return sum;
}

时间复杂度:O(nlgn)

运用递归思想,一层一层分解,最终解决问题。效率还好,有助于理解分治与递归,可以尝试使用。

 

方法四:动态规划

这是最常见的方法了,简单有效,好理解。

状态转移方程:sum[i] = max{sum[i-1]+a[i],a[i]}. (sum[i]记录以a[i]为子序列末端的最大序子列连续和)

其实完全可以不用开数组,累计sum直到sum + a < a,把sum赋值为a,更新最大值就行了。

//动态规划算法
int MaxSum(int n)
{
    int sum=0,b=0;
    for(int i=0;i<n;i++)
    {
        if(b>0) b+=a[i];
        else b=a[i];
        if(b>sum) sum=b;
    }
    return sum;
}

时间复杂度:O(n)

这是好用的求最大子序列的方法了,墙裂推荐!

 

相关题目练习:

hdu 1003:http://acm.hdu.edu.cn/showproblem.php?pid=1003

hdu 1231:http://acm.hdu.edu.cn/showproblem.php?pid=1231

 

作者: AlvinZH

出处: http://www.cnblogs.com/AlvinZH/

本人Github:https://github.com/Pacsiy/JobDu

本文版权归作者AlvinZH和博客园所有,欢迎转载和商用,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.

posted @ 2017-05-02 13:14  AlvinZH  阅读(16727)  评论(0编辑  收藏  举报