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

原创 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;
}


 

 

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

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

动态规划经典题目:最大连续子序列和

最大连续子序列和问题         给定k个整数的序列{N1,N2,...,Nk },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1  注:为方便起见,如果所有整数均为...
  • zhaobryant
  • zhaobryant
  • 2014年08月13日 15:22
  • 4754

最大连续子序列和:动态规划经典题目(2)

问题描述:       连续子序列最大和,其实就是求一个序列中连续的子序列中元素和最大的那个。       比如例如给定序列:            { -2, 11, -4, 13, -5,...
  • samjustin1
  • samjustin1
  • 2016年07月27日 10:47
  • 4144

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

最大子序列和的几种解法
  • u013451048
  • u013451048
  • 2015年03月07日 20:49
  • 270

求最大子序列的线性时间复杂度的解法的理解

今天在看《C++语言描述(第3版)_Mark Allen Weiss》时,看到 第二章的四种求解最大子序列的方法,对于第四种解法,书上有言:“这是许多聪明算法的典型:运行时间是明显的,但正确性则不明显...
  • hellokingqwe
  • hellokingqwe
  • 2015年09月06日 21:06
  • 394

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

最大子序列和的一个线性时间解法及解释。
  • wenwuchige
  • wenwuchige
  • 2015年03月12日 14:57
  • 583

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

HDU1231:给定K个整数的序列{ N1, N2, …, NK },其任意连续子序列可表示为{ Ni, Ni+1, …, Nj },其中 1 ...
  • UncleJokerly
  • UncleJokerly
  • 2017年07月11日 13:12
  • 178

Maximum Sum 最大子矩阵和+dp+(最大连续子序列的变形)

Maximum Sum  Background A problem that is simple to solve in one dimension is often mu...
  • u012870383
  • u012870383
  • 2014年07月18日 20:52
  • 574

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

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

java 之连续子序列最大和问题的四个解法

import java.util.Random; public final class MaxSumTest {     static private int seqStart = 0;   ...
  • zhang434
  • zhang434
  • 2014年02月17日 17:19
  • 1518
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:连续最大子序列的几种解法
举报原因:
原因补充:

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