连续最大子序列的几种解法

原创 2013年12月02日 16:46:55

所谓最大连续子序列,就是求出给定一串数字中连续的那一段元素和的最大值。

举例如:

给定序列:2 3 -1 4 7  则最大子序列的值应为4+7=11.

 

先说第一种方法:暴力枚举数组中的元素,不断求和,进行更新即可。可是时间复杂度上一般承受不了。O(n^3)的时间复杂度确实对一般的问题很难接受。

 

第二种:把a[0]初始化为max值,则枚举n个位置,每次把sum置为0,然后从位置i开始计算从i开始的最大连续子序列和的大小,如果大于max,则更新max。

部分代码如下:

inline int maxsequence(int arr[], int len)
{
    int max = arr[0]; //初始化最大值为第一个元素
    for (int i=0; i<len; i++) {
        int sum = 0; //sum必须清零
        for (int j=i; j<len; j++) { //从位置i开始计算从i开始的最大连续子序列和的大小,如果大于max,则更新max。
            sum += arr[j];
            if (sum > max)
                max = sum;
        }
    }
    return max;
}


 

 

第三种:分治法。原序列可以分为两部分,不断递归计算出这两块序列的和,然后从中间向两端遍历,找到最大的序列的和。

部分代码如下:

/*求三个数最大值*/
inline int max3(int i, int j, int k)
{
    if (i>=j && i>=k)
        return i;
    return max3(j, k, i);
}

inline int maxsequence2(int a[], int l, int u)
{
    if (l > u) return 0;
    if (l == u) return a[l];
    int m = (l + u) / 2;

    /*求横跨左右的最大连续子序列左半部分*/
    int lmax=a[m], lsum=0;
    for (int i=m; i>=l; i--)
    {
        lsum += a[i];
        if (lsum > lmax)
            lmax = lsum;
    }

    /*求横跨左右的最大连续子序列右半部分*/
    int rmax=a[m+1], rsum = 0;
    for (int i=m+1; i<=u; i++)
     {
            rsum += a[i];
            if (rsum > rmax)
            rmax = rsum;
    }
    return max3(lmax+rmax, maxsequence2(a, l, m), maxsequence2(a, m+1, u)); //返回三者最大值
}


 

第四种:读入的时候预处理出一个前缀和数组,即sum[i]表示a[o]+a[1]+a[2]+.....+a[i-1];

然后又是枚举了,但实际这个复杂度也偏高,效率不太理想。

 

第五种:DP,最简单的DP吧,这个不知道DP的人也可以很容易写出来,用dp[i]表示以a[i]结尾所获得的最大值,那么显然有:dp[i]=max(dp[i-1]+a[i],a[i]);不断更新这个dp数组即可,时间复杂度最优,O(n)。

 

另外值得一提的是,还有一种变形的最大连续子序列的问题,简单的如这个题的B题

最常见的也是稍微有点麻烦的就是求最大子矩阵的问题,以前一直不会算,最后稍微想下就明白了。给出的是二维数组,但是求的值相当于还是应用的最大连续子序列的思想。具体做法就是把矩阵转换为一维的来算。

也就是枚举矩阵的连续几行的合并,这样就转换为一维的了,再用最大子序列的算法去求,更新最大值就可以了

下面附上几种求连续最大子序列的代码:

 

 

#include <iostream>
#include <cstdio>
#include <cstring>

int dp[501][501];
using namespace std;

inline int maxsequence(int arr[], int len)
{
    int max = arr[0]; //初始化最大值为第一个元素
    for (int i=0; i<len; i++) {
        int sum = 0; //sum必须清零
        for (int j=i; j<len; j++) { //从位置i开始计算从i开始的最大连续子序列和的大小,如果大于max,则更新max。
            sum += arr[j];
            if (sum > max)
                max = sum;
        }
    }
    return max;
}

/*求三个数最大值*/
inline int max3(int i, int j, int k)
{
    if (i>=j && i>=k)
        return i;
    return max3(j, k, i);
}

inline int maxsequence2(int a[], int l, int u)
{
    if (l > u) return 0;
    if (l == u) return a[l];
    int m = (l + u) / 2;

    /*求横跨左右的最大连续子序列左半部分*/
    int lmax=a[m], lsum=0;
    for (int i=m; i>=l; i--)
    {
        lsum += a[i];
        if (lsum > lmax)
            lmax = lsum;
    }

    /*求横跨左右的最大连续子序列右半部分*/
    int rmax=a[m+1], rsum = 0;
    for (int i=m+1; i<=u; i++)
     {
            rsum += a[i];
            if (rsum > rmax)
            rmax = rsum;
    }
    return max3(lmax+rmax, maxsequence2(a, l, m), maxsequence2(a, m+1, u)); //返回三者最大值
}

int maxsequence3(int a[], int len)
{
    int maxsum, maxhere;
    maxsum = maxhere = a[0];   //初始化最大和为a【0】
    for (int i=1; i<len; i++) {
        if (maxhere <= 0)
            maxhere = a[i];  //如果前面位置最大连续子序列和小于等于0,则以当前位置i结尾的最大连续子序列和为a[i]
        else
            maxhere += a[i]; //如果前面位置最大连续子序列和大于0,则以当前位置i结尾的最大连续子序列和为它们两者之和
        if (maxhere > maxsum) {
            maxsum = maxhere;  //更新最大连续子序列和
        }
    }
    return maxsum;
}

int main()
{
    int a[100];
    int n;
    while(cin>>n)
    {
        for(int i=0;i<n;i++)
        {
            cin>>a[i];
        }
        cout<<maxsequence3(a,n)<<endl;
    }
    return 0;
}


 

 

相关文章推荐

hdu(杭电oj)第一页题目题解

第一页有几题没写,有机会补上(嗯,忘了就是另一回事了)。

求最大连续子序列和4种算法解析

1.        题目描述: 给出一个长度为N的序列:a1,a2,……,an,求最大连续和。找到1= 2.        算法1 1)        思路解析:枚举所有可能的子序列的和,通过三...

标题:最大子序列和的几种解法(总结)

最大子序列和的几种解法

最大子序列和的线性时间解法

最大子序列和的一个线性时间解法及解释。

HDU1231最大连续子序列&Uva108Maximum Sum最大子矩阵

HDU1231:给定K个整数的序列{ N1, N2, …, NK },其任意连续子序列可表示为{ Ni, Ni+1, …, Nj },其中 1 ...

HDU 1081 最大子矩阵(求最大连续子序列和)

这一题是求最大子矩阵,以后肯定还会经常碰到这样一类的题目 上原题; Problem Description Given a two-dimensional array of posi...
  • Kerwun
  • Kerwun
  • 2016年08月23日 00:58
  • 565

hdu 1231 最大连续子序列 yy+dp+数据结构解法

1:线段树解法 对于每一个i求出最大的(i-k)区间内的sum值及id #include #include #include #include #include #include #include ...

HDU1231 最大连续子序列【最大子段和+DP】

问题链接:HDU1231 最大连续子序列。 问题简述:参见上述链接。 问题分析:计算最大子段和问题,是一个经典的动态规划问题。 程序说明: 这个算法可以说是最为快速简洁的算法,其计算复杂度为O(n...

C 最大子序列算法

  • 2015年03月14日 17:46
  • 2KB
  • 下载

最大子序列求和

  • 2014年09月08日 22:13
  • 388B
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:连续最大子序列的几种解法
举报原因:
原因补充:

(最多只允许输入30个字)